package org.example.generator;

import lombok.extern.slf4j.Slf4j;
import org.example.entity.CustomerInfo;
import org.example.entity.CustomerOrder;
import org.example.entity.CustomerRepayPlan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;

import org.example.service.CustomerInfoService;
import org.example.service.CustomerOrderService;
import org.example.service.CustomerRepayPlanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.example.mapper.CustomerInfoMapper;
import org.example.mapper.CustomerOrderMapper;
import org.example.mapper.CustomerRepayPlanMapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.transaction.annotation.Transactional;

/**
 * 数据生成器 - 重新设计版本
 * 满足以下要求：
 * 1. 总量20亿在途贷款余额，总投放50亿放款金额
 * 2. 浩瀚小贷在途余额不超过6亿
 * 3. 2023年7月开始放款，前6个月只有浩瀚小贷，后面多产品分布
 * 4. 盈峰小贷占30%，浩瀚小贷占50%，新网银行和江山小贷占20%
 * 5. 每月放款数据递增
 * 6. Vintage逾期率5%左右，迁徙率小于100%
 * 7. 支持批量插入数据库，每2000条批量插入一次
 */
@Component
@Slf4j
public class DataGenerator {
    private static final Logger log = LoggerFactory.getLogger(DataGenerator.class);
    private static final AtomicLong customerIdCounter = new AtomicLong(System.currentTimeMillis() * 10000);
// 使用新的ID生成器
     private static final CustomerIdGenerator idGenerator = new CustomerIdGenerator();

    @Autowired
    private CustomerInfoMapper customerInfoMapper;

    @Autowired
    private CustomerOrderMapper customerOrderMapper;

    @Autowired
    private CustomerRepayPlanMapper customerRepayPlanMapper;

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    @Autowired
    private CustomerInfoService customerInfoService;

    @Autowired
    private CustomerOrderService customerOrderService;

    @Autowired
    private CustomerRepayPlanService customerRepayPlanService;

    // 数据生成配置
    private static final BigDecimal TARGET_OUTSTANDING_AMOUNT = new BigDecimal("2000000000"); // 20亿在途余额
    private static final BigDecimal TARGET_LOAN_AMOUNT = new BigDecimal("5000000000"); // 50亿总投放
    private static final BigDecimal HAOHAN_MAX_OUTSTANDING = new BigDecimal("600000000"); // 浩瀚小贷最大在途余额6亿
    private static final int BATCH_SIZE = 2000; // 批量插入大小
    private static final LocalDate START_DATE = LocalDate.of(2023, 7, 1); // 2023年7月开始
//        private static final LocalDate START_DATE = LocalDate.of(2025, 1, 1); //  todo产品比例
    private static final int HAOHAN_ONLY_MONTHS = 6; // 前6个月只有浩瀚小贷
    private static final int THREAD_POOL_SIZE = 8; // 线程池大小

    // Vintage配置 - 基于真实业务数据的波状图模式（降低逾期率到5%左右）
    private static final double FIRST_PERIOD_OVERDUE_RATE = 0.0001; // 第一期存在逾期（调整到0.01%）
    private static final double PEAK_OVERDUE_RATE = 0.001; // 峰值逾期率（调整到0.1%）
    private static final double NORMAL_REPAY_WITHIN_3_DAYS_RATE = 0.95; // 95%在3天内正常还款
    private static final double OVERDUE_AFTER_REPAY_RATE = 0.02; // 2%逾期后还款（降低）


    // 城市列表（排除西藏、新疆、甘肃、青海）
    private static final String[] CITIES = {
            // 直辖市
            "北京市", "上海市", "天津市", "重庆市",

            // 河北省
            "石家庄市", "唐山市", "秦皇岛市", "邯郸市", "邢台市", "保定市", "张家口市", "承德市", "沧州市", "廊坊市", "衡水市",

            // 山西省
            "太原市", "大同市", "阳泉市", "长治市", "晋城市", "朔州市", "晋中市", "运城市", "忻州市", "临汾市", "吕梁市",

            // 内蒙古自治区
            "呼和浩特市", "包头市", "乌海市", "赤峰市", "通辽市", "鄂尔多斯市", "呼伦贝尔市", "巴彦淖尔市", "乌兰察布市", "兴安盟", "锡林郭勒盟", "阿拉善盟",

            // 辽宁省
            "沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市", "丹东市", "锦州市", "营口市", "阜新市", "辽阳市", "盘锦市", "铁岭市", "朝阳市", "葫芦岛市",

            // 吉林省
            "长春市", "吉林市", "四平市", "辽源市", "通化市", "白山市", "松原市", "白城市", "延边朝鲜族自治州",

            // 黑龙江省
            "哈尔滨市", "齐齐哈尔市", "鸡西市", "鹤岗市", "双鸭山市", "大庆市", "伊春市", "佳木斯市", "七台河市", "牡丹江市", "黑河市", "绥化市", "大兴安岭地区",

            // 江苏省
            "南京市", "无锡市", "徐州市", "常州市", "苏州市", "南通市", "连云港市", "淮安市", "盐城市", "扬州市", "镇江市", "泰州市", "宿迁市",

            // 浙江省
            "杭州市", "宁波市", "温州市", "嘉兴市", "湖州市", "绍兴市", "金华市", "衢州市", "舟山市", "台州市", "丽水市",

            // 安徽省
            "合肥市", "芜湖市", "蚌埠市", "淮南市", "马鞍山市", "淮北市", "铜陵市", "安庆市", "黄山市", "滁州市", "阜阳市", "宿州市", "六安市", "亳州市", "池州市", "宣城市",

            // 福建省
            "福州市", "厦门市", "莆田市", "三明市", "泉州市", "漳州市", "南平市", "龙岩市", "宁德市",

            // 江西省
            "南昌市", "景德镇市", "萍乡市", "九江市", "新余市", "鹰潭市", "赣州市", "吉安市", "宜春市", "抚州市", "上饶市",

            // 山东省
            "济南市", "青岛市", "淄博市", "枣庄市", "东营市", "烟台市", "潍坊市", "济宁市", "泰安市", "威海市", "日照市", "临沂市", "德州市", "聊城市", "滨州市", "菏泽市",

            // 河南省
            "郑州市", "开封市", "洛阳市", "平顶山市", "安阳市", "鹤壁市", "新乡市", "焦作市", "濮阳市", "许昌市", "漯河市", "三门峡市", "南阳市", "商丘市", "信阳市", "周口市", "驻马店市", "济源市",

            // 湖北省
            "武汉市", "黄石市", "十堰市", "宜昌市", "襄阳市", "鄂州市", "荆门市", "孝感市", "荆州市", "黄冈市", "咸宁市", "随州市", "恩施土家族苗族自治州", "仙桃市", "潜江市", "天门市", "神农架林区",

            // 湖南省
            "长沙市", "株洲市", "湘潭市", "衡阳市", "邵阳市", "岳阳市", "常德市", "张家界市", "益阳市", "郴州市", "永州市", "怀化市", "娄底市", "湘西土家族苗族自治州",

            // 广东省
            "广州市", "韶关市", "深圳市", "珠海市", "汕头市", "佛山市", "江门市", "湛江市", "茂名市", "肇庆市", "惠州市", "梅州市", "汕尾市", "河源市", "阳江市", "清远市", "东莞市", "中山市", "潮州市", "揭阳市", "云浮市",

            // 广西壮族自治区
            "南宁市", "柳州市", "桂林市", "梧州市", "北海市", "防城港市", "钦州市", "贵港市", "玉林市", "百色市", "贺州市", "河池市", "来宾市", "崇左市",

            // 海南省
            "海口市", "三亚市", "三沙市", "儋州市", "五指山市", "琼海市", "文昌市", "万宁市", "东方市", "定安县", "屯昌县", "澄迈县", "临高县", "白沙黎族自治县", "昌江黎族自治县", "乐东黎族自治县", "陵水黎族自治县", "保亭黎族苗族自治县", "琼中黎族苗族自治县",

            // 四川省
            "成都市", "自贡市", "攀枝花市", "泸州市", "德阳市", "绵阳市", "广元市", "遂宁市", "内江市", "乐山市", "南充市", "眉山市", "宜宾市", "广安市", "达州市", "雅安市", "巴中市", "资阳市", "阿坝藏族羌族自治州", "甘孜藏族自治州", "凉山彝族自治州",

            // 贵州省
            "贵阳市", "六盘水市", "遵义市", "安顺市", "毕节市", "铜仁市", "黔西南布依族苗族自治州", "黔东南苗族侗族自治州", "黔南布依族苗族自治州",

            // 云南省
            "昆明市", "曲靖市", "玉溪市", "保山市", "昭通市", "丽江市", "普洱市", "临沧市", "楚雄彝族自治州", "红河哈尼族彝族自治州", "文山壮族苗族自治州", "西双版纳傣族自治州", "大理白族自治州", "德宏傣族景颇族自治州", "怒江傈僳族自治州", "迪庆藏族自治州",

            // 陕西省
            "西安市", "铜川市", "宝鸡市", "咸阳市", "渭南市", "延安市", "汉中市", "榆林市", "安康市", "商洛市",

            // 宁夏回族自治区
            "银川市", "石嘴山市", "吴忠市", "固原市", "中卫市"
    };

    // 渠道来源
    private static final String[] SOURCES = {"闪信", "速贝", "哈啰", "360", "全民", "人品", "拍拍","融360","嘉银","小薇钱包",
            "乐享借","金彩贷","快手","小鹅钱包","便荔卡包","钱家","享用钱","百度","云盛花","51信用卡","花财树","转转商城","融安分期","省呗",

            "薪有钱","微博借钱","兑吧","小薇钱包","云盛花","51信用卡","便荔卡包","嘉银"};

    // 学历（按分布比例）
    public static final String[] EDUCATIONS = {
            "大专", "大专", "大专", // 30%
            "中专职高技校", "中专职高技校", // 15%
            "高中", "高中", // 20%
            "本科", "本科", // 20%
            "小学", "初中", "硕士", "其他" // 15%
    };

    // 职业（按分布比例）
    private static final String[] OCCUPATIONS = {
            "商业、服务业人员", "商业、服务业人员", "商业、服务业人员", "商业、服务业人员", "商业、服务业人员", // 50%
            "国家机关、党群组织、企业、事业单位负责人", "专业技术人员", "办事人员和有关人员", "农、林、牧、渔水利业生产人员", "生产、运输设备操作人员及有关人员", "不便分类的其他从业人员", // 30%
            "其他", "其他" // 20%
    };

    // 婚姻状况（按分布比例）
    private static final String[] MARITAL_STATUS = {
            "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", "已婚", // 65%
            "未婚", "未婚", "未婚", "未婚", "未婚", // 25%
            "其他", "其他", // 7%
            "离异" // 3%
    };

    // 贷款期限
    private static final int[] LOAN_TERMS = {3, 6, 6,12,12,12,12,12,12,12,12,12,12,12,12};

    // 还款方式
    public static final String[] REPAY_TYPES = {"等额本息", "等额本金"};

    // 贷款用途（按分布比例）
    public static final String[] LOAN_PURPOSES = {
            "消费", "消费", "消费", "消费", "消费", "消费", // 60%
            "其他", "装修", "医疗", "教育", "旅游" // 40%
    };

    // 贷款用途
    private static final String[] LOAN_USES = {"消费", "装修", "教育", "医疗", "旅游", "其他"};

    // 产品名称和分布权重（按放款金额）
    private static final Map<String, Double> PRODUCT_DISTRIBUTION = Map.of(
            "浩瀚小贷", 0.25,  // 30%
            "盈峰小贷", 0.20,  // 30%
            "新网银行", 0.15,  // 20%
            "江山小贷", 0.15,  // 20%
            "融越小贷", 0.10,  // 20%
            "码果科技", 0.07,   // 20%
            "国晟小贷", 0.08   // 20%
    );

    // 迁徙率配置（M2催回率降到20%-30%）
    private static final Map<String, Double> MIGRATION_RATES = Map.of(
            "M1_M2", 0.25,   // M1到M2迁徙率25%（M2催回率75%）
            "M2_M3", 0.20,   // M2到M3迁徙率20%（M2催回率80%）
            "M3_M4", 0.15,   // M3到M4迁徙率15%
            "M4_M5", 0.10,   // M4到M5迁徙率10%
            "M5_M6", 0.08    // M5到M6迁徙率8%
    );

    private static final String[] PRODUCT_NAMES = {"新网银行", "盈峰小贷", "江山小贷", "浩瀚小贷"};
    private static final String[] PRODUCT_M = {
            "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1", "M1",//96%
            "M2", "M2", "M2",//3%
            "M3",//1%
            "M4", "M5", "M6"//0% (共3个，每个约0%)
    };

    // 身份证前缀映射（全国除西藏、新疆、甘肃、青海）
    private static final Map<String, String> CITY_ID_PREFIX = new HashMap<>();

    private static final Map<String, Double> OVERDAY = Map.of(
            "D1_4", 0.26,//10%
            "D4_7", 0.35,//10%
            "D7_15", 0.40,//4%
            "D15_30", 0.46,//6%
            "D30_60", 0.62,//2%---18%
            "D60_90", 0.70,//2%--8
            "D90_120", 0.72//1%
//            "D120_150", 0.20
    );

    //方案2：重新定义OVERDAY为累积概率
    private static final Map<String, Double> OVERDAY_CUMULATIVE = Map.of(
            "D1_7", 0.07,      // 0-7%
            "D7_15", 0.12,     // 7-12%
            "D15_30", 0.17,    // 12-17%
            "D30_60", 0.45,    // 17-45%
            "D60_90", 0.82,    // 45-82%
            "D90_120", 0.99    // 82-97%
    );
    private static final String[] OVERDAY_TYPES = {"等额本息", "等额本金"};

    public static final Map<String, String> CITY_CODE_MAP = new HashMap<>();
    
    // 城市到省份的映射关系
    public static final Map<String, String> CITY_TO_PROVINCE_MAP = new HashMap<>();

    static {
        // 直辖市
        CITY_CODE_MAP.put("北京市", "110000");
        CITY_CODE_MAP.put("上海市", "310000");
        CITY_CODE_MAP.put("天津市", "120000");
        CITY_CODE_MAP.put("重庆市", "500000");

        // 河北省
        CITY_CODE_MAP.put("石家庄市", "130100");
        CITY_CODE_MAP.put("唐山市", "130200");
        CITY_CODE_MAP.put("秦皇岛市", "130300");
        CITY_CODE_MAP.put("邯郸市", "130400");
        CITY_CODE_MAP.put("邢台市", "130500");
        CITY_CODE_MAP.put("保定市", "130600");
        CITY_CODE_MAP.put("张家口市", "130700");
        CITY_CODE_MAP.put("承德市", "130800");
        CITY_CODE_MAP.put("沧州市", "130900");
        CITY_CODE_MAP.put("廊坊市", "131000");
        CITY_CODE_MAP.put("衡水市", "131100");

        // 山西省
        CITY_CODE_MAP.put("太原市", "140100");
        CITY_CODE_MAP.put("大同市", "140200");
        CITY_CODE_MAP.put("阳泉市", "140300");
        CITY_CODE_MAP.put("长治市", "140400");
        CITY_CODE_MAP.put("晋城市", "140500");
        CITY_CODE_MAP.put("朔州市", "140600");
        CITY_CODE_MAP.put("晋中市", "140700");
        CITY_CODE_MAP.put("运城市", "140800");
        CITY_CODE_MAP.put("忻州市", "140900");
        CITY_CODE_MAP.put("临汾市", "141000");
        CITY_CODE_MAP.put("吕梁市", "141100");

        // 辽宁省
        CITY_CODE_MAP.put("沈阳市", "210100");
        CITY_CODE_MAP.put("大连市", "210200");
        CITY_CODE_MAP.put("鞍山市", "210300");
        CITY_CODE_MAP.put("抚顺市", "210400");
        CITY_CODE_MAP.put("本溪市", "210500");
        CITY_CODE_MAP.put("丹东市", "210600");
        CITY_CODE_MAP.put("锦州市", "210700");
        CITY_CODE_MAP.put("营口市", "210800");
        CITY_CODE_MAP.put("阜新市", "210900");
        CITY_CODE_MAP.put("辽阳市", "211000");
        CITY_CODE_MAP.put("盘锦市", "211100");
        CITY_CODE_MAP.put("铁岭市", "211200");
        CITY_CODE_MAP.put("朝阳市", "211300");
        CITY_CODE_MAP.put("葫芦岛市", "211400");

        // 江苏省
        CITY_CODE_MAP.put("南京市", "320100");
        CITY_CODE_MAP.put("无锡市", "320200");
        CITY_CODE_MAP.put("徐州市", "320300");
        CITY_CODE_MAP.put("常州市", "320400");
        CITY_CODE_MAP.put("苏州市", "320500");
        CITY_CODE_MAP.put("南通市", "320600");
        CITY_CODE_MAP.put("连云港市", "320700");
        CITY_CODE_MAP.put("淮安市", "320800");
        CITY_CODE_MAP.put("盐城市", "320900");
        CITY_CODE_MAP.put("扬州市", "321000");
        CITY_CODE_MAP.put("镇江市", "321100");
        CITY_CODE_MAP.put("泰州市", "321200");
        CITY_CODE_MAP.put("宿迁市", "321300");

        // 浙江省
        CITY_CODE_MAP.put("杭州市", "330100");
        CITY_CODE_MAP.put("宁波市", "330200");
        CITY_CODE_MAP.put("温州市", "330300");
        CITY_CODE_MAP.put("嘉兴市", "330400");
        CITY_CODE_MAP.put("湖州市", "330500");
        CITY_CODE_MAP.put("绍兴市", "330600");
        CITY_CODE_MAP.put("金华市", "330700");
        CITY_CODE_MAP.put("衢州市", "330800");
        CITY_CODE_MAP.put("舟山市", "330900");
        CITY_CODE_MAP.put("台州市", "331000");
        CITY_CODE_MAP.put("丽水市", "331100");

        // 安徽省
        CITY_CODE_MAP.put("合肥市", "340100");
        CITY_CODE_MAP.put("芜湖市", "340200");
        CITY_CODE_MAP.put("蚌埠市", "340300");
        CITY_CODE_MAP.put("淮南市", "340400");
        CITY_CODE_MAP.put("马鞍山市", "340500");
        CITY_CODE_MAP.put("淮北市", "340600");
        CITY_CODE_MAP.put("铜陵市", "340700");
        CITY_CODE_MAP.put("安庆市", "340800");
        CITY_CODE_MAP.put("黄山市", "341000");
        CITY_CODE_MAP.put("滁州市", "341100");
        CITY_CODE_MAP.put("阜阳市", "341200");
        CITY_CODE_MAP.put("宿州市", "341300");
        CITY_CODE_MAP.put("六安市", "341500");
        CITY_CODE_MAP.put("亳州市", "341600");
        CITY_CODE_MAP.put("池州市", "341700");
        CITY_CODE_MAP.put("宣城市", "341800");

        // 福建省
        CITY_CODE_MAP.put("福州市", "350100");
        CITY_CODE_MAP.put("厦门市", "350200");
        CITY_CODE_MAP.put("莆田市", "350300");
        CITY_CODE_MAP.put("三明市", "350400");
        CITY_CODE_MAP.put("泉州市", "350500");
        CITY_CODE_MAP.put("漳州市", "350600");
        CITY_CODE_MAP.put("南平市", "350700");
        CITY_CODE_MAP.put("龙岩市", "350800");
        CITY_CODE_MAP.put("宁德市", "350900");

        // 江西省
        CITY_CODE_MAP.put("南昌市", "360100");
        CITY_CODE_MAP.put("景德镇市", "360200");
        CITY_CODE_MAP.put("萍乡市", "360300");
        CITY_CODE_MAP.put("九江市", "360400");
        CITY_CODE_MAP.put("新余市", "360500");
        CITY_CODE_MAP.put("鹰潭市", "360600");
        CITY_CODE_MAP.put("赣州市", "360700");
        CITY_CODE_MAP.put("吉安市", "360800");
        CITY_CODE_MAP.put("宜春市", "360900");
        CITY_CODE_MAP.put("抚州市", "361000");
        CITY_CODE_MAP.put("上饶市", "361100");

        // 山东省
        CITY_CODE_MAP.put("济南市", "370100");
        CITY_CODE_MAP.put("青岛市", "370200");
        CITY_CODE_MAP.put("淄博市", "370300");
        CITY_CODE_MAP.put("枣庄市", "370400");
        CITY_CODE_MAP.put("东营市", "370500");
        CITY_CODE_MAP.put("烟台市", "370600");
        CITY_CODE_MAP.put("潍坊市", "370700");
        CITY_CODE_MAP.put("济宁市", "370800");
        CITY_CODE_MAP.put("泰安市", "370900");
        CITY_CODE_MAP.put("威海市", "371000");
        CITY_CODE_MAP.put("日照市", "371100");
        CITY_CODE_MAP.put("临沂市", "371300");
        CITY_CODE_MAP.put("德州市", "371400");
        CITY_CODE_MAP.put("聊城市", "371500");
        CITY_CODE_MAP.put("滨州市", "371600");
        CITY_CODE_MAP.put("菏泽市", "371700");
        //以下是信贷的 todo 车贷的话要去掉
        // 河南省
        CITY_CODE_MAP.put("郑州市", "410100");
        CITY_CODE_MAP.put("开封市", "410200");
        CITY_CODE_MAP.put("洛阳市", "410300");
        CITY_CODE_MAP.put("平顶山市", "410400");
        CITY_CODE_MAP.put("安阳市", "410500");
        CITY_CODE_MAP.put("鹤壁市", "410600");
        CITY_CODE_MAP.put("新乡市", "410700");
        CITY_CODE_MAP.put("焦作市", "410800");
        CITY_CODE_MAP.put("濮阳市", "410900");
        CITY_CODE_MAP.put("许昌市", "411000");
        CITY_CODE_MAP.put("漯河市", "411100");
        CITY_CODE_MAP.put("三门峡市", "411200");
        CITY_CODE_MAP.put("南阳市", "411300");
        CITY_CODE_MAP.put("商丘市", "411400");
        CITY_CODE_MAP.put("信阳市", "411500");
        CITY_CODE_MAP.put("周口市", "411600");
        CITY_CODE_MAP.put("驻马店市", "411700");
        CITY_CODE_MAP.put("济源市", "419001");

        // 湖北省
        CITY_CODE_MAP.put("武汉市", "420100");
        CITY_CODE_MAP.put("黄石市", "420200");
        CITY_CODE_MAP.put("十堰市", "420300");
        CITY_CODE_MAP.put("宜昌市", "420500");
        CITY_CODE_MAP.put("襄阳市", "420600");
        CITY_CODE_MAP.put("鄂州市", "420700");
        CITY_CODE_MAP.put("荆门市", "420800");
        CITY_CODE_MAP.put("孝感市", "420900");
        CITY_CODE_MAP.put("荆州市", "421000");
        CITY_CODE_MAP.put("黄冈市", "421100");
        CITY_CODE_MAP.put("咸宁市", "421200");
        CITY_CODE_MAP.put("随州市", "421300");
        CITY_CODE_MAP.put("恩施土家族苗族自治州", "422800");
        CITY_CODE_MAP.put("仙桃市", "429004");
        CITY_CODE_MAP.put("潜江市", "429005");
        CITY_CODE_MAP.put("天门市", "429006");
        CITY_CODE_MAP.put("神农架林区", "429021");

        // 湖南省
        CITY_CODE_MAP.put("长沙市", "430100");
        CITY_CODE_MAP.put("株洲市", "430200");
        CITY_CODE_MAP.put("湘潭市", "430300");
        CITY_CODE_MAP.put("衡阳市", "430400");
        CITY_CODE_MAP.put("邵阳市", "430500");
        CITY_CODE_MAP.put("岳阳市", "430600");
        CITY_CODE_MAP.put("常德市", "430700");
        CITY_CODE_MAP.put("张家界市", "430800");
        CITY_CODE_MAP.put("益阳市", "430900");
        CITY_CODE_MAP.put("郴州市", "431000");
        CITY_CODE_MAP.put("永州市", "431100");
        CITY_CODE_MAP.put("怀化市", "431200");
        CITY_CODE_MAP.put("娄底市", "431300");
        CITY_CODE_MAP.put("湘西土家族苗族自治州", "433100");

        // 广东省
        CITY_CODE_MAP.put("广州市", "440100");
        CITY_CODE_MAP.put("韶关市", "440200");
        CITY_CODE_MAP.put("深圳市", "440300");
        CITY_CODE_MAP.put("珠海市", "440400");
        CITY_CODE_MAP.put("汕头市", "440500");
        CITY_CODE_MAP.put("佛山市", "440600");
        CITY_CODE_MAP.put("江门市", "440700");
        CITY_CODE_MAP.put("湛江市", "440800");
        CITY_CODE_MAP.put("茂名市", "440900");
        CITY_CODE_MAP.put("肇庆市", "441200");
        CITY_CODE_MAP.put("惠州市", "441300");
        CITY_CODE_MAP.put("梅州市", "441400");
        CITY_CODE_MAP.put("汕尾市", "441500");
        CITY_CODE_MAP.put("河源市", "441600");
        CITY_CODE_MAP.put("阳江市", "441700");
        CITY_CODE_MAP.put("清远市", "441800");
        CITY_CODE_MAP.put("东莞市", "441900");
        CITY_CODE_MAP.put("中山市", "442000");
        CITY_CODE_MAP.put("潮州市", "445100");
        CITY_CODE_MAP.put("揭阳市", "445200");
        CITY_CODE_MAP.put("云浮市", "445300");

        // 广西壮族自治区
        CITY_CODE_MAP.put("南宁市", "450100");
        CITY_CODE_MAP.put("柳州市", "450200");
        CITY_CODE_MAP.put("桂林市", "450300");
        CITY_CODE_MAP.put("梧州市", "450400");
        CITY_CODE_MAP.put("北海市", "450500");
        CITY_CODE_MAP.put("防城港市", "450600");
        CITY_CODE_MAP.put("钦州市", "450700");
        CITY_CODE_MAP.put("贵港市", "450800");
        CITY_CODE_MAP.put("玉林市", "450900");
        CITY_CODE_MAP.put("百色市", "451000");
        CITY_CODE_MAP.put("贺州市", "451100");
        CITY_CODE_MAP.put("河池市", "451200");
        CITY_CODE_MAP.put("来宾市", "451300");
        CITY_CODE_MAP.put("崇左市", "451400");

        // 海南省
        CITY_CODE_MAP.put("海口市", "460100");
        CITY_CODE_MAP.put("三亚市", "460200");
        CITY_CODE_MAP.put("三沙市", "460300");
        CITY_CODE_MAP.put("儋州市", "460400");
        CITY_CODE_MAP.put("五指山市", "469001");
        CITY_CODE_MAP.put("琼海市", "469002");
        CITY_CODE_MAP.put("文昌市", "469005");
        CITY_CODE_MAP.put("万宁市", "469006");
        CITY_CODE_MAP.put("东方市", "469007");
        CITY_CODE_MAP.put("定安县", "469021");
        CITY_CODE_MAP.put("屯昌县", "469022");
        CITY_CODE_MAP.put("澄迈县", "469023");
        CITY_CODE_MAP.put("临高县", "469024");
        CITY_CODE_MAP.put("白沙黎族自治县", "469025");
        CITY_CODE_MAP.put("昌江黎族自治县", "469026");
        CITY_CODE_MAP.put("乐东黎族自治县", "469027");
        CITY_CODE_MAP.put("陵水黎族自治县", "469028");
        CITY_CODE_MAP.put("保亭黎族苗族自治县", "469029");
        CITY_CODE_MAP.put("琼中黎族苗族自治县", "469030");

        // 四川省
        CITY_CODE_MAP.put("成都市", "510100");
        CITY_CODE_MAP.put("自贡市", "510300");
        CITY_CODE_MAP.put("攀枝花市", "510400");
        CITY_CODE_MAP.put("泸州市", "510500");
        CITY_CODE_MAP.put("德阳市", "510600");
        CITY_CODE_MAP.put("绵阳市", "510700");
        CITY_CODE_MAP.put("广元市", "510800");
        CITY_CODE_MAP.put("遂宁市", "510900");
        CITY_CODE_MAP.put("内江市", "511000");
        CITY_CODE_MAP.put("乐山市", "511100");
        CITY_CODE_MAP.put("南充市", "511300");
        CITY_CODE_MAP.put("眉山市", "511400");
        CITY_CODE_MAP.put("宜宾市", "511500");
        CITY_CODE_MAP.put("广安市", "511600");
        CITY_CODE_MAP.put("达州市", "511700");
        CITY_CODE_MAP.put("雅安市", "511800");
        CITY_CODE_MAP.put("巴中市", "511900");
        CITY_CODE_MAP.put("资阳市", "512000");
        CITY_CODE_MAP.put("阿坝藏族羌族自治州", "513200");
        CITY_CODE_MAP.put("甘孜藏族自治州", "513300");
        CITY_CODE_MAP.put("凉山彝族自治州", "513400");

        // 贵州省
        CITY_CODE_MAP.put("贵阳市", "520100");
        CITY_CODE_MAP.put("六盘水市", "520200");
        CITY_CODE_MAP.put("遵义市", "520300");
        CITY_CODE_MAP.put("安顺市", "520400");
        CITY_CODE_MAP.put("毕节市", "520500");
        CITY_CODE_MAP.put("铜仁市", "520600");
        CITY_CODE_MAP.put("黔西南布依族苗族自治州", "522300");
        CITY_CODE_MAP.put("黔东南苗族侗族自治州", "522600");
        CITY_CODE_MAP.put("黔南布依族苗族自治州", "522700");

        // 云南省
        CITY_CODE_MAP.put("昆明市", "530100");
        CITY_CODE_MAP.put("曲靖市", "530300");
        CITY_CODE_MAP.put("玉溪市", "530400");
        CITY_CODE_MAP.put("保山市", "530500");
        CITY_CODE_MAP.put("昭通市", "530600");
        CITY_CODE_MAP.put("丽江市", "530700");
        CITY_CODE_MAP.put("普洱市", "530800");
        CITY_CODE_MAP.put("临沧市", "530900");
        CITY_CODE_MAP.put("楚雄彝族自治州", "532300");
        CITY_CODE_MAP.put("红河哈尼族彝族自治州", "532500");
        CITY_CODE_MAP.put("文山壮族苗族自治州", "532600");
        CITY_CODE_MAP.put("西双版纳傣族自治州", "532800");
        CITY_CODE_MAP.put("大理白族自治州", "532900");
        CITY_CODE_MAP.put("德宏傣族景颇族自治州", "533100");
        CITY_CODE_MAP.put("怒江傈僳族自治州", "533300");
        CITY_CODE_MAP.put("迪庆藏族自治州", "533400");

        // 西藏自治区  不允许
//        CITY_CODE_MAP.put("拉萨市", "540100");
//        CITY_CODE_MAP.put("日喀则市", "540200");
//        CITY_CODE_MAP.put("昌都市", "540300");
//        CITY_CODE_MAP.put("林芝市", "540400");
//        CITY_CODE_MAP.put("山南市", "540500");
//        CITY_CODE_MAP.put("那曲市", "540600");
//        CITY_CODE_MAP.put("阿里地区", "542500");

        // 陕西省
        CITY_CODE_MAP.put("西安市", "610100");
        CITY_CODE_MAP.put("铜川市", "610200");
        CITY_CODE_MAP.put("宝鸡市", "610300");
        CITY_CODE_MAP.put("咸阳市", "610400");
        CITY_CODE_MAP.put("渭南市", "610500");
        CITY_CODE_MAP.put("延安市", "610600");
        CITY_CODE_MAP.put("汉中市", "610700");
        CITY_CODE_MAP.put("榆林市", "610800");
        CITY_CODE_MAP.put("安康市", "610900");
        CITY_CODE_MAP.put("商洛市", "611000");

        // 甘肃省
        CITY_CODE_MAP.put("兰州市", "620100");
        CITY_CODE_MAP.put("嘉峪关市", "620200");
        CITY_CODE_MAP.put("金昌市", "620300");
        CITY_CODE_MAP.put("白银市", "620400");
        CITY_CODE_MAP.put("天水市", "620500");
        CITY_CODE_MAP.put("武威市", "620600");
        CITY_CODE_MAP.put("张掖市", "620700");
        CITY_CODE_MAP.put("平凉市", "620800");
        CITY_CODE_MAP.put("酒泉市", "620900");
        CITY_CODE_MAP.put("庆阳市", "621000");
        CITY_CODE_MAP.put("定西市", "621100");
        CITY_CODE_MAP.put("陇南市", "621200");
        CITY_CODE_MAP.put("临夏回族自治州", "622900");
        CITY_CODE_MAP.put("甘南藏族自治州", "623000");

        // 青海省
        CITY_CODE_MAP.put("西宁市", "630100");
        CITY_CODE_MAP.put("海东市", "630200");
        CITY_CODE_MAP.put("海北藏族自治州", "632200");
        CITY_CODE_MAP.put("黄南藏族自治州", "632300");
        CITY_CODE_MAP.put("海南藏族自治州", "632500");
        CITY_CODE_MAP.put("果洛藏族自治州", "632600");
        CITY_CODE_MAP.put("玉树藏族自治州", "632700");
        CITY_CODE_MAP.put("海西蒙古族藏族自治州", "632800");

        // 宁夏回族自治区
        CITY_CODE_MAP.put("银川市", "640100");
        CITY_CODE_MAP.put("石嘴山市", "640200");
        CITY_CODE_MAP.put("吴忠市", "640300");
        CITY_CODE_MAP.put("固原市", "640400");
        CITY_CODE_MAP.put("中卫市", "640500");

        // 新疆维吾尔自治区  不允许
//        CITY_CODE_MAP.put("乌鲁木齐市", "650100");
//        CITY_CODE_MAP.put("克拉玛依市", "650200");
//        CITY_CODE_MAP.put("吐鲁番市", "650400");
//        CITY_CODE_MAP.put("哈密市", "650500");
//        CITY_CODE_MAP.put("昌吉回族自治州", "652300");
//        CITY_CODE_MAP.put("博尔塔拉蒙古自治州", "652700");
//        CITY_CODE_MAP.put("巴音郭楞蒙古自治州", "652800");
//        CITY_CODE_MAP.put("阿克苏地区", "652900");
//        CITY_CODE_MAP.put("克孜勒苏柯尔克孜自治州", "653000");
//        CITY_CODE_MAP.put("喀什地区", "653100");
//        CITY_CODE_MAP.put("和田地区", "653200");
//        CITY_CODE_MAP.put("伊犁哈萨克自治州", "654000");
//        CITY_CODE_MAP.put("塔城地区", "654200");
//        CITY_CODE_MAP.put("阿勒泰地区", "654300");
//        CITY_CODE_MAP.put("石河子市", "659001");
//        CITY_CODE_MAP.put("阿拉尔市", "659002");
//        CITY_CODE_MAP.put("图木舒克市", "659003");
//        CITY_CODE_MAP.put("五家渠市", "659004");
//        CITY_CODE_MAP.put("北屯市", "659005");
//        CITY_CODE_MAP.put("铁门关市", "659006");
//        CITY_CODE_MAP.put("双河市", "659007");
//        CITY_CODE_MAP.put("可克达拉市", "659008");
//        CITY_CODE_MAP.put("昆玉市", "659009");
//        CITY_CODE_MAP.put("胡杨河市", "659010");

        // 内蒙古自治区
        CITY_CODE_MAP.put("呼和浩特市", "150100");
        CITY_CODE_MAP.put("包头市", "150200");
        CITY_CODE_MAP.put("乌海市", "150300");
        CITY_CODE_MAP.put("赤峰市", "150400");
        CITY_CODE_MAP.put("通辽市", "150500");
        CITY_CODE_MAP.put("鄂尔多斯市", "150600");
        CITY_CODE_MAP.put("呼伦贝尔市", "150700");
        CITY_CODE_MAP.put("巴彦淖尔市", "150800");
        CITY_CODE_MAP.put("乌兰察布市", "150900");
        CITY_CODE_MAP.put("兴安盟", "152200");
        CITY_CODE_MAP.put("锡林郭勒盟", "152500");
        CITY_CODE_MAP.put("阿拉善盟", "152900");

        // 吉林省
        CITY_CODE_MAP.put("长春市", "220100");
        CITY_CODE_MAP.put("吉林市", "220200");
        CITY_CODE_MAP.put("四平市", "220300");
        CITY_CODE_MAP.put("辽源市", "220400");
        CITY_CODE_MAP.put("通化市", "220500");
        CITY_CODE_MAP.put("白山市", "220600");
        CITY_CODE_MAP.put("松原市", "220700");
        CITY_CODE_MAP.put("白城市", "220800");
        CITY_CODE_MAP.put("延边朝鲜族自治州", "222400");

        // 黑龙江省
        CITY_CODE_MAP.put("哈尔滨市", "230100");
        CITY_CODE_MAP.put("齐齐哈尔市", "230200");
        CITY_CODE_MAP.put("鸡西市", "230300");
        CITY_CODE_MAP.put("鹤岗市", "230400");
        CITY_CODE_MAP.put("双鸭山市", "230500");
        CITY_CODE_MAP.put("大庆市", "230600");
        CITY_CODE_MAP.put("伊春市", "230700");
        CITY_CODE_MAP.put("佳木斯市", "230800");
        CITY_CODE_MAP.put("七台河市", "230900");
        CITY_CODE_MAP.put("牡丹江市", "231000");
        CITY_CODE_MAP.put("黑河市", "231100");
        CITY_CODE_MAP.put("绥化市", "231200");
        CITY_CODE_MAP.put("大兴安岭地区", "232700");
        
        // 初始化城市到省份的映射关系
        initCityToProvinceMap();
    }
    
    /**
     * 根据城市名称获取对应的省份
     * @param cityName 城市名称
     * @return 省份名称，如果找不到则返回"未知省份"
     */
    public static String getProvinceByCity(String cityName) {
        return CITY_TO_PROVINCE_MAP.getOrDefault(cityName, "北京市");
    }
    
    /**
     * 计算基于放款时间的调整因子
     * 23年7月到12月：逾期概率高于平均的50%，这几个月基本相同
     * 24年1月到25年9月：逾期率基础相同，保持总的逾期率在4%左右
     * @param loanDate 放款日期
     * @return 时间调整因子
     */
    private static double calculateTimeAdjustmentFactor(LocalDate loanDate) {
        int year = loanDate.getYear();
        int month = loanDate.getMonthValue();
        
        // 判断时间段
        if (year == 2023 && month >= 7 && month <= 12) {
            // 23年7月到12月：逾期概率高于平均的50%，这几个月基本相同
            return 1.5; // 固定1.5倍，比平均高50%
        } else if ((year == 2024) || (year == 2025 && month <= 9)) {
            // 24年1月到25年9月：逾期率基础相同
            return 1.0; // 固定1.0倍，保持基础逾期率
        } else {
            // 其他时间段：使用默认值
            return 1.0;
        }
    }
    
    /**
     * 初始化城市到省份的映射关系
     */
    private static void initCityToProvinceMap() {
        // 直辖市
        CITY_TO_PROVINCE_MAP.put("北京市", "北京市");
        CITY_TO_PROVINCE_MAP.put("上海市", "上海市");
        CITY_TO_PROVINCE_MAP.put("天津市", "天津市");
        CITY_TO_PROVINCE_MAP.put("重庆市", "重庆市");

        // 河北省
        CITY_TO_PROVINCE_MAP.put("石家庄市", "河北省");
        CITY_TO_PROVINCE_MAP.put("唐山市", "河北省");
        CITY_TO_PROVINCE_MAP.put("秦皇岛市", "河北省");
        CITY_TO_PROVINCE_MAP.put("邯郸市", "河北省");
        CITY_TO_PROVINCE_MAP.put("邢台市", "河北省");
        CITY_TO_PROVINCE_MAP.put("保定市", "河北省");
        CITY_TO_PROVINCE_MAP.put("张家口市", "河北省");
        CITY_TO_PROVINCE_MAP.put("承德市", "河北省");
        CITY_TO_PROVINCE_MAP.put("沧州市", "河北省");
        CITY_TO_PROVINCE_MAP.put("廊坊市", "河北省");
        CITY_TO_PROVINCE_MAP.put("衡水市", "河北省");

        // 山西省
        CITY_TO_PROVINCE_MAP.put("太原市", "山西省");
        CITY_TO_PROVINCE_MAP.put("大同市", "山西省");
        CITY_TO_PROVINCE_MAP.put("阳泉市", "山西省");
        CITY_TO_PROVINCE_MAP.put("长治市", "山西省");
        CITY_TO_PROVINCE_MAP.put("晋城市", "山西省");
        CITY_TO_PROVINCE_MAP.put("朔州市", "山西省");
        CITY_TO_PROVINCE_MAP.put("晋中市", "山西省");
        CITY_TO_PROVINCE_MAP.put("运城市", "山西省");
        CITY_TO_PROVINCE_MAP.put("忻州市", "山西省");
        CITY_TO_PROVINCE_MAP.put("临汾市", "山西省");
        CITY_TO_PROVINCE_MAP.put("吕梁市", "山西省");

        // 辽宁省
        CITY_TO_PROVINCE_MAP.put("沈阳市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("大连市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("鞍山市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("抚顺市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("本溪市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("丹东市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("锦州市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("营口市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("阜新市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("辽阳市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("盘锦市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("铁岭市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("朝阳市", "辽宁省");
        CITY_TO_PROVINCE_MAP.put("葫芦岛市", "辽宁省");

        // 吉林省
        CITY_TO_PROVINCE_MAP.put("长春市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("吉林市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("四平市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("辽源市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("通化市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("白山市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("松原市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("白城市", "吉林省");
        CITY_TO_PROVINCE_MAP.put("延边朝鲜族自治州", "吉林省");

        // 黑龙江省
        CITY_TO_PROVINCE_MAP.put("哈尔滨市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("齐齐哈尔市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("鸡西市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("鹤岗市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("双鸭山市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("大庆市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("伊春市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("佳木斯市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("七台河市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("牡丹江市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("黑河市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("绥化市", "黑龙江省");
        CITY_TO_PROVINCE_MAP.put("大兴安岭地区", "黑龙江省");

        // 江苏省
        CITY_TO_PROVINCE_MAP.put("南京市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("无锡市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("徐州市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("常州市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("苏州市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("南通市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("连云港市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("淮安市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("盐城市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("扬州市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("镇江市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("泰州市", "江苏省");
        CITY_TO_PROVINCE_MAP.put("宿迁市", "江苏省");

        // 浙江省
        CITY_TO_PROVINCE_MAP.put("杭州市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("宁波市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("温州市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("嘉兴市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("湖州市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("绍兴市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("金华市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("衢州市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("舟山市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("台州市", "浙江省");
        CITY_TO_PROVINCE_MAP.put("丽水市", "浙江省");

        // 安徽省
        CITY_TO_PROVINCE_MAP.put("合肥市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("芜湖市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("蚌埠市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("淮南市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("马鞍山市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("淮北市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("铜陵市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("安庆市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("黄山市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("滁州市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("阜阳市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("宿州市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("六安市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("亳州市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("池州市", "安徽省");
        CITY_TO_PROVINCE_MAP.put("宣城市", "安徽省");

        // 福建省
        CITY_TO_PROVINCE_MAP.put("福州市", "福建省");
        CITY_TO_PROVINCE_MAP.put("厦门市", "福建省");
        CITY_TO_PROVINCE_MAP.put("莆田市", "福建省");
        CITY_TO_PROVINCE_MAP.put("三明市", "福建省");
        CITY_TO_PROVINCE_MAP.put("泉州市", "福建省");
        CITY_TO_PROVINCE_MAP.put("漳州市", "福建省");
        CITY_TO_PROVINCE_MAP.put("南平市", "福建省");
        CITY_TO_PROVINCE_MAP.put("龙岩市", "福建省");
        CITY_TO_PROVINCE_MAP.put("宁德市", "福建省");

        // 江西省
        CITY_TO_PROVINCE_MAP.put("南昌市", "江西省");
        CITY_TO_PROVINCE_MAP.put("景德镇市", "江西省");
        CITY_TO_PROVINCE_MAP.put("萍乡市", "江西省");
        CITY_TO_PROVINCE_MAP.put("九江市", "江西省");
        CITY_TO_PROVINCE_MAP.put("新余市", "江西省");
        CITY_TO_PROVINCE_MAP.put("鹰潭市", "江西省");
        CITY_TO_PROVINCE_MAP.put("赣州市", "江西省");
        CITY_TO_PROVINCE_MAP.put("吉安市", "江西省");
        CITY_TO_PROVINCE_MAP.put("宜春市", "江西省");
        CITY_TO_PROVINCE_MAP.put("抚州市", "江西省");
        CITY_TO_PROVINCE_MAP.put("上饶市", "江西省");

        // 山东省
        CITY_TO_PROVINCE_MAP.put("济南市", "山东省");
        CITY_TO_PROVINCE_MAP.put("青岛市", "山东省");
        CITY_TO_PROVINCE_MAP.put("淄博市", "山东省");
        CITY_TO_PROVINCE_MAP.put("枣庄市", "山东省");
        CITY_TO_PROVINCE_MAP.put("东营市", "山东省");
        CITY_TO_PROVINCE_MAP.put("烟台市", "山东省");
        CITY_TO_PROVINCE_MAP.put("潍坊市", "山东省");
        CITY_TO_PROVINCE_MAP.put("济宁市", "山东省");
        CITY_TO_PROVINCE_MAP.put("泰安市", "山东省");
        CITY_TO_PROVINCE_MAP.put("威海市", "山东省");
        CITY_TO_PROVINCE_MAP.put("日照市", "山东省");
        CITY_TO_PROVINCE_MAP.put("临沂市", "山东省");
        CITY_TO_PROVINCE_MAP.put("德州市", "山东省");
        CITY_TO_PROVINCE_MAP.put("聊城市", "山东省");
        CITY_TO_PROVINCE_MAP.put("滨州市", "山东省");
        CITY_TO_PROVINCE_MAP.put("菏泽市", "山东省");

        // 河南省
        CITY_TO_PROVINCE_MAP.put("郑州市", "河南省");
        CITY_TO_PROVINCE_MAP.put("开封市", "河南省");
        CITY_TO_PROVINCE_MAP.put("洛阳市", "河南省");
        CITY_TO_PROVINCE_MAP.put("平顶山市", "河南省");
        CITY_TO_PROVINCE_MAP.put("安阳市", "河南省");
        CITY_TO_PROVINCE_MAP.put("鹤壁市", "河南省");
        CITY_TO_PROVINCE_MAP.put("新乡市", "河南省");
        CITY_TO_PROVINCE_MAP.put("焦作市", "河南省");
        CITY_TO_PROVINCE_MAP.put("濮阳市", "河南省");
        CITY_TO_PROVINCE_MAP.put("许昌市", "河南省");
        CITY_TO_PROVINCE_MAP.put("漯河市", "河南省");
        CITY_TO_PROVINCE_MAP.put("三门峡市", "河南省");
        CITY_TO_PROVINCE_MAP.put("南阳市", "河南省");
        CITY_TO_PROVINCE_MAP.put("商丘市", "河南省");
        CITY_TO_PROVINCE_MAP.put("信阳市", "河南省");
        CITY_TO_PROVINCE_MAP.put("周口市", "河南省");
        CITY_TO_PROVINCE_MAP.put("驻马店市", "河南省");
        CITY_TO_PROVINCE_MAP.put("济源市", "河南省");

        // 湖北省
        CITY_TO_PROVINCE_MAP.put("武汉市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("黄石市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("十堰市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("宜昌市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("襄阳市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("鄂州市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("荆门市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("孝感市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("荆州市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("黄冈市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("咸宁市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("随州市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("恩施土家族苗族自治州", "湖北省");
        CITY_TO_PROVINCE_MAP.put("仙桃市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("潜江市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("天门市", "湖北省");
        CITY_TO_PROVINCE_MAP.put("神农架林区", "湖北省");

        // 湖南省
        CITY_TO_PROVINCE_MAP.put("长沙市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("株洲市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("湘潭市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("衡阳市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("邵阳市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("岳阳市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("常德市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("张家界市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("益阳市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("郴州市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("永州市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("怀化市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("娄底市", "湖南省");
        CITY_TO_PROVINCE_MAP.put("湘西土家族苗族自治州", "湖南省");

        // 广东省
        CITY_TO_PROVINCE_MAP.put("广州市", "广东省");
        CITY_TO_PROVINCE_MAP.put("韶关市", "广东省");
        CITY_TO_PROVINCE_MAP.put("深圳市", "广东省");
        CITY_TO_PROVINCE_MAP.put("珠海市", "广东省");
        CITY_TO_PROVINCE_MAP.put("汕头市", "广东省");
        CITY_TO_PROVINCE_MAP.put("佛山市", "广东省");
        CITY_TO_PROVINCE_MAP.put("江门市", "广东省");
        CITY_TO_PROVINCE_MAP.put("湛江市", "广东省");
        CITY_TO_PROVINCE_MAP.put("茂名市", "广东省");
        CITY_TO_PROVINCE_MAP.put("肇庆市", "广东省");
        CITY_TO_PROVINCE_MAP.put("惠州市", "广东省");
        CITY_TO_PROVINCE_MAP.put("梅州市", "广东省");
        CITY_TO_PROVINCE_MAP.put("汕尾市", "广东省");
        CITY_TO_PROVINCE_MAP.put("河源市", "广东省");
        CITY_TO_PROVINCE_MAP.put("阳江市", "广东省");
        CITY_TO_PROVINCE_MAP.put("清远市", "广东省");
        CITY_TO_PROVINCE_MAP.put("东莞市", "广东省");
        CITY_TO_PROVINCE_MAP.put("中山市", "广东省");
        CITY_TO_PROVINCE_MAP.put("潮州市", "广东省");
        CITY_TO_PROVINCE_MAP.put("揭阳市", "广东省");
        CITY_TO_PROVINCE_MAP.put("云浮市", "广东省");

        // 广西壮族自治区
        CITY_TO_PROVINCE_MAP.put("南宁市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("柳州市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("桂林市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("梧州市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("北海市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("防城港市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("钦州市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("贵港市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("玉林市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("百色市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("贺州市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("河池市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("来宾市", "广西壮族自治区");
        CITY_TO_PROVINCE_MAP.put("崇左市", "广西壮族自治区");

        // 海南省
        CITY_TO_PROVINCE_MAP.put("海口市", "海南省");
        CITY_TO_PROVINCE_MAP.put("三亚市", "海南省");
        CITY_TO_PROVINCE_MAP.put("三沙市", "海南省");
        CITY_TO_PROVINCE_MAP.put("儋州市", "海南省");

        // 四川省
        CITY_TO_PROVINCE_MAP.put("成都市", "四川省");
        CITY_TO_PROVINCE_MAP.put("自贡市", "四川省");
        CITY_TO_PROVINCE_MAP.put("攀枝花市", "四川省");
        CITY_TO_PROVINCE_MAP.put("泸州市", "四川省");
        CITY_TO_PROVINCE_MAP.put("德阳市", "四川省");
        CITY_TO_PROVINCE_MAP.put("绵阳市", "四川省");
        CITY_TO_PROVINCE_MAP.put("广元市", "四川省");
        CITY_TO_PROVINCE_MAP.put("遂宁市", "四川省");
        CITY_TO_PROVINCE_MAP.put("内江市", "四川省");
        CITY_TO_PROVINCE_MAP.put("乐山市", "四川省");
        CITY_TO_PROVINCE_MAP.put("南充市", "四川省");
        CITY_TO_PROVINCE_MAP.put("眉山市", "四川省");
        CITY_TO_PROVINCE_MAP.put("宜宾市", "四川省");
        CITY_TO_PROVINCE_MAP.put("广安市", "四川省");
        CITY_TO_PROVINCE_MAP.put("达州市", "四川省");
        CITY_TO_PROVINCE_MAP.put("雅安市", "四川省");
        CITY_TO_PROVINCE_MAP.put("巴中市", "四川省");
        CITY_TO_PROVINCE_MAP.put("资阳市", "四川省");
        CITY_TO_PROVINCE_MAP.put("阿坝藏族羌族自治州", "四川省");
        CITY_TO_PROVINCE_MAP.put("甘孜藏族自治州", "四川省");
        CITY_TO_PROVINCE_MAP.put("凉山彝族自治州", "四川省");

        // 贵州省
        CITY_TO_PROVINCE_MAP.put("贵阳市", "贵州省");
        CITY_TO_PROVINCE_MAP.put("六盘水市", "贵州省");
        CITY_TO_PROVINCE_MAP.put("遵义市", "贵州省");
        CITY_TO_PROVINCE_MAP.put("安顺市", "贵州省");
        CITY_TO_PROVINCE_MAP.put("毕节市", "贵州省");
        CITY_TO_PROVINCE_MAP.put("铜仁市", "贵州省");
        CITY_TO_PROVINCE_MAP.put("黔西南布依族苗族自治州", "贵州省");
        CITY_TO_PROVINCE_MAP.put("黔东南苗族侗族自治州", "贵州省");
        CITY_TO_PROVINCE_MAP.put("黔南布依族苗族自治州", "贵州省");

        // 云南省
        CITY_TO_PROVINCE_MAP.put("昆明市", "云南省");
        CITY_TO_PROVINCE_MAP.put("曲靖市", "云南省");
        CITY_TO_PROVINCE_MAP.put("玉溪市", "云南省");
        CITY_TO_PROVINCE_MAP.put("保山市", "云南省");
        CITY_TO_PROVINCE_MAP.put("昭通市", "云南省");
        CITY_TO_PROVINCE_MAP.put("丽江市", "云南省");
        CITY_TO_PROVINCE_MAP.put("普洱市", "云南省");
        CITY_TO_PROVINCE_MAP.put("临沧市", "云南省");
        CITY_TO_PROVINCE_MAP.put("楚雄彝族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("红河哈尼族彝族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("文山壮族苗族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("西双版纳傣族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("大理白族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("德宏傣族景颇族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("怒江傈僳族自治州", "云南省");
        CITY_TO_PROVINCE_MAP.put("迪庆藏族自治州", "云南省");

        // 西藏自治区
        CITY_TO_PROVINCE_MAP.put("拉萨市", "西藏自治区");
        CITY_TO_PROVINCE_MAP.put("日喀则市", "西藏自治区");
        CITY_TO_PROVINCE_MAP.put("昌都市", "西藏自治区");
        CITY_TO_PROVINCE_MAP.put("林芝市", "西藏自治区");
        CITY_TO_PROVINCE_MAP.put("山南市", "西藏自治区");
        CITY_TO_PROVINCE_MAP.put("那曲市", "西藏自治区");
        CITY_TO_PROVINCE_MAP.put("阿里地区", "西藏自治区");

        // 陕西省
        CITY_TO_PROVINCE_MAP.put("西安市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("铜川市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("宝鸡市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("咸阳市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("渭南市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("延安市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("汉中市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("榆林市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("安康市", "陕西省");
        CITY_TO_PROVINCE_MAP.put("商洛市", "陕西省");

        // 甘肃省
        CITY_TO_PROVINCE_MAP.put("兰州市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("嘉峪关市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("金昌市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("白银市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("天水市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("武威市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("张掖市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("平凉市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("酒泉市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("庆阳市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("定西市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("陇南市", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("临夏回族自治州", "甘肃省");
        CITY_TO_PROVINCE_MAP.put("甘南藏族自治州", "甘肃省");

        // 青海省
        CITY_TO_PROVINCE_MAP.put("西宁市", "青海省");
        CITY_TO_PROVINCE_MAP.put("海东市", "青海省");
        CITY_TO_PROVINCE_MAP.put("海北藏族自治州", "青海省");
        CITY_TO_PROVINCE_MAP.put("黄南藏族自治州", "青海省");
        CITY_TO_PROVINCE_MAP.put("海南藏族自治州", "青海省");
        CITY_TO_PROVINCE_MAP.put("果洛藏族自治州", "青海省");
        CITY_TO_PROVINCE_MAP.put("玉树藏族自治州", "青海省");
        CITY_TO_PROVINCE_MAP.put("海西蒙古族藏族自治州", "青海省");

        // 宁夏回族自治区
        CITY_TO_PROVINCE_MAP.put("银川市", "宁夏回族自治区");
        CITY_TO_PROVINCE_MAP.put("石嘴山市", "宁夏回族自治区");
        CITY_TO_PROVINCE_MAP.put("吴忠市", "宁夏回族自治区");
        CITY_TO_PROVINCE_MAP.put("固原市", "宁夏回族自治区");
        CITY_TO_PROVINCE_MAP.put("中卫市", "宁夏回族自治区");

        // 新疆维吾尔自治区
        CITY_TO_PROVINCE_MAP.put("乌鲁木齐市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("克拉玛依市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("吐鲁番市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("哈密市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("昌吉回族自治州", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("博尔塔拉蒙古自治州", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("巴音郭楞蒙古自治州", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("阿克苏地区", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("克孜勒苏柯尔克孜自治州", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("喀什地区", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("和田地区", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("伊犁哈萨克自治州", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("塔城地区", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("阿勒泰地区", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("石河子市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("阿拉尔市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("图木舒克市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("五家渠市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("北屯市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("铁门关市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("双河市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("可克达拉市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("昆玉市", "新疆维吾尔自治区");
        CITY_TO_PROVINCE_MAP.put("胡杨河市", "新疆维吾尔自治区");

        // 内蒙古自治区
        CITY_TO_PROVINCE_MAP.put("呼和浩特市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("包头市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("乌海市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("赤峰市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("通辽市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("鄂尔多斯市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("呼伦贝尔市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("巴彦淖尔市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("乌兰察布市", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("兴安盟", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("锡林郭勒盟", "内蒙古自治区");
        CITY_TO_PROVINCE_MAP.put("阿拉善盟", "内蒙古自治区");
    }

    private static final Random random = new Random();

    // 每月放款递增配置
    private static final BigDecimal MONTHLY_INCREASE_RATE = new BigDecimal("0.1"); // 每月递增10%

    /**
     * 生成指定月份的数据
     */
    public static List<CustomerOrder> generateMonthlyData(LocalDate month, int targetOrderCount) {
        List<CustomerOrder> orders = new ArrayList<>();
        List<CustomerInfo> customers = new ArrayList<>();
        List<CustomerRepayPlan> repayPlans = new ArrayList<>();

        // 计算该月份的放款金额（递增）
        long daysFromStart = month.toEpochDay() - START_DATE.toEpochDay();

        // 确定产品分布
        Map<String, Integer> productDistribution = calculateProductDistribution(month, targetOrderCount);

        for (Map.Entry<String, Integer> entry : productDistribution.entrySet()) {
            String productName = entry.getKey();
            int orderCount = entry.getValue();

            for (int i = 0; i < orderCount; i++) {
                // 生成客户信息
                CustomerInfo customer = generateCustomerInfo(month);
                customers.add(customer);

                // 生成订单
                CustomerOrder order = generateCustomerOrder(customer, month, productName);
                orders.add(order);

                // 生成还款计划
                List<CustomerRepayPlan> plans = generateRepayPlan(order, 0, 0);
                repayPlans.addAll(plans);
            }
        }

        return orders;
    }

    /**
     * 计算产品分布
     */
    private static Map<String, Integer> calculateProductDistribution(LocalDate month, int totalOrders) {
        Map<String, Integer> distribution = new HashMap<>();

//         判断是否在前6个月（只有浩瀚小贷）
        if (month.isBefore(START_DATE.plusMonths(HAOHAN_ONLY_MONTHS))) {
            distribution.put("浩瀚小贷", totalOrders);
        } else {
            // 按权重分配
            int haohanCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("浩瀚小贷"));
            int yingfengCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("盈峰小贷"));
            int xinwangCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("新网银行"));
            int rongyueCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("融越小贷"));
            int shuoguoCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("码果科技"));
            int guoshengCount = (int) (totalOrders * PRODUCT_DISTRIBUTION.get("国晟小贷"));
            int jiangshanCount = totalOrders - haohanCount - yingfengCount - xinwangCount-rongyueCount-shuoguoCount-guoshengCount;

            distribution.put("浩瀚小贷", haohanCount);
            distribution.put("盈峰小贷", yingfengCount);
            distribution.put("新网银行", xinwangCount);
            distribution.put("江山小贷", jiangshanCount);
            distribution.put("融越小贷", rongyueCount);
            distribution.put("码果科技", shuoguoCount);
            distribution.put("国晟小贷", guoshengCount);
        }

        return distribution;
    }

    /**
     * 生成用户信息
     */
    public static CustomerInfo generateCustomerInfo(LocalDate orderDate) {
        CustomerInfo customer = new CustomerInfo();
        customer.setId(customerIdCounter.incrementAndGet());
        // 使用示例
        Map.Entry<String, String> randomEntry = getRandomCityCode();
        String city = "";
        String code = "";
        if (randomEntry != null) {
            city = randomEntry.getKey();
            code = randomEntry.getValue();
        }
        // 随机选择城市
        customer.setSaleCityName(city);
        
        // 根据城市设置对应的省份
        String province = getProvinceByCity(city);
        customer.setProvince(province);

        // 生成脱敏姓名
        customer.setPlName(generateMaskedName());

        // 生成脱敏手机号
        customer.setPlPhone(generateMaskedPhone());

        // 性别（男75%，女25%）
        customer.setGender(random.nextDouble() < 0.75 ? "男" : "女");

        // 生成脱敏身份证号（根据性别生成倒数第二位）
        customer.setPlIdNo(generateMaskedIdNo(code, customer.getGender()));

        // 年龄（正态分布，没有18以下的）
        customer.setAge(generateNormalDistributedAge());

        // 学历
        customer.setEducation(EDUCATIONS[random.nextInt(EDUCATIONS.length)]);

        // 职业（按分布比例）
        customer.setOccupation(OCCUPATIONS[random.nextInt(OCCUPATIONS.length)]);

        // 婚姻状况
        customer.setMaritalStatus(MARITAL_STATUS[random.nextInt(MARITAL_STATUS.length)]);

        // 渠道来源
        customer.setSource(SOURCES[random.nextInt(SOURCES.length)]);

        // 登录状态
        customer.setLoginStatus("通过");

        // 创建时间（与订单生成时间一致，时分秒在06:00:00到23:00:00之间随机）
        int hour = 6 + random.nextInt(18); // 6-23点
        int minute = random.nextInt(60);   // 0-59分
        int second = random.nextInt(60);   // 0-59秒
        String timeStr = String.format("%02d:%02d:%02d", hour, minute, second);
        customer.setCreatedTime(orderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " " + timeStr);

        return customer;
    }

    /**
     * 生成客户订单
     */
    public static CustomerOrder generateCustomerOrder(CustomerInfo customerInfo, LocalDate loanDate, String productName) {
        CustomerOrder order = new CustomerOrder();

        // 订单号
        order.setOrderNo("ORD" + customerInfo.getId());
        order.setCustomerId(customerInfo.getId());

        // 用户信息
        order.setPlName(customerInfo.getPlName());
        order.setPlPhone(customerInfo.getPlPhone());
        order.setPlIdNo(customerInfo.getPlIdNo());
        order.setSaleCityName(customerInfo.getSaleCityName());

        // 放款时间
        order.setFrTime(loanDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

        // 贷款期限
        int term = LOAN_TERMS[random.nextInt(LOAN_TERMS.length)];
        order.setLoanTerm(term + "月");

        // 对客利率（18%或24%）
        String rate = random.nextBoolean() ? "18%" : "24%";
        order.setProductRate(rate);

        // 贷款金额（平均5000左右，精确到百位）
        BigDecimal loanAmount = BigDecimal.valueOf((3000 + random.nextInt(4000)) / 100 * 100)
                .setScale(2, RoundingMode.HALF_UP);
        order.setLoanAmount(loanAmount);

        // 产品名称（直接使用传入的参数）
        order.setProductName(productName);

        // 还款方式
        String repayType = REPAY_TYPES[random.nextInt(REPAY_TYPES.length)];
        // 如果还款方式是先息后本，则贷款期限必须是1
//        if ("先息后本".equals(repayType)) {
//            order.setLoanTerm("1月");
//            term = 1;
//        }
        order.setRepayType(repayType);

        // 贷款用途（按分布比例）
        order.setLoanUse(LOAN_PURPOSES[random.nextInt(LOAN_PURPOSES.length)]);
        LocalDate now = LocalDate.of(2025, 9, 30);

        // 状态和结清日期（2%提前还款，均匀分布在不同放款时间）
        boolean isEarlyRepay = false;
        // 使用loanDate和orderNo生成均匀分布的随机数，按照loanDate逐渐递增
        double earlyRepayRandom = generateUniformRandomFromLoanDateTermAndOrderNo(loanDate,term, order.getOrderNo());
        double overdueRepayRandom = generateUniformRandomFromLoanDateTermAndOrderNo(loanDate,term, order.getOrderNo());

        // 为每种期限设置不同的提前还款比例
        if (term == 3) {
            isEarlyRepay = earlyRepayRandom < 0.016; // 1.6%提前结清
        } else if (term == 6) {
            isEarlyRepay = earlyRepayRandom < 0.032; // 1.6%提前结清
        } else if (term == 12) {
            isEarlyRepay = earlyRepayRandom < 0.032; // 1.7%提前结清
        }
        // 使用loanDate、orderNo和term生成均匀分布的随机数，按照term期数爬坡递增
        double overdueRandom = generateUniformRandomFromLoanDateOrderNoAndTerm(loanDate, order.getOrderNo(), term);

        //状态和逾期处理（均匀分布在不同放款时间）
        boolean isOverdue = false; // 是否当前逾期
        boolean isOverdueRepaid = false; // 是否逾期已还
        // 获取年月信息计算递增比例
//        int year = loanDate.getYear();
//        int month = loanDate.getMonthValue();
//        int totalMonths = (year - 2023) * 12 + (month - 1);
//        double monthIncrement = Math.min(totalMonths * 0.002, 0.03); // 每月递增0.1%，最大3%
//        monthIncrement = Math.max(monthIncrement, 0.0);
        // 为每种期限设置不同的逾期比例，按照放款月数frTime平均分配
        // 根据LocalDate loanDate的年月来判断逾期率
        if (term == 3) {
            // 基础逾期比例5%，加上年月递增
            if (overdueRandom < 0.044) {
                isOverdue = true; // 当前逾期 这个参数可以调整逾期率的大小
            }
            //逾期已还和逾期分隔开--从结清的0.032开始
            if (overdueRandom  < 0.052) {//
                isOverdueRepaid = true; // 4%逾期已还  这个参数可以调整vin的大小
            }
        } else if (term == 6) {
            // 6月期：5%逾期，5%逾期已还
            // 基础逾期比例6%，加上年月递增
            if (overdueRandom< 0.046) {
                isOverdue = true; // 5%当前逾期
            }
            if (overdueRandom  < 0.052) {//最开始是0.023
                isOverdueRepaid = true; // 5%逾期已还
            }
        } else if (term == 12) {
            // 12月期：基础逾期比例5%，加上年月递增
            if (overdueRandom < 0.044) {//
                isOverdue = true; // 6%当前逾期
            }
            if (overdueRandom  < 0.053) {//最开始是0.034



                isOverdueRepaid = true; // 4%逾期已还
            }
        }

        // 计算订单到期时间
        LocalDate orderDueDate = loanDate.plusMonths(term);


        if (isEarlyRepay) {
            // 提前还款逻辑：结清日期在还款周期一半前后
            int halfTerm = term / 2;
            int settleMonth = halfTerm + random.nextInt(halfTerm + 1);
            LocalDate setSettleDate = loanDate.plusMonths(settleMonth);

            if (setSettleDate.isBefore(now)) {
                order.setStatus("已结清");
                order.setSettleDate(setSettleDate);
                order.setRemainPayAmount(BigDecimal.ZERO);
            } else {
                // 提前还款但结清日期在未来，设置为未结清
                order.setStatus("未结清");
                order.setSettleDate(null);
                // 计算剩余金额（简化计算）
                long remainingMonths = orderDueDate.toEpochDay() - now.toEpochDay();
                remainingMonths = Math.max(0, remainingMonths / 30);
                order.setRemainPayAmount(loanAmount.multiply(BigDecimal.valueOf(remainingMonths))
                        .divide(BigDecimal.valueOf(term), 2, RoundingMode.HALF_UP));
            }
        } else if (isOverdue) {
            //是否当前逾期
            order.setStatus("逾期");
        } else if (isOverdueRepaid) {
            //是否当前逾期
            order.setStatus("逾期已还");//todo 剩余金额更新
        } else {
            // 正常还款逻辑：根据到期时间判断状态
            if (orderDueDate.isBefore(now)) {
                // 订单已到期，但为了模拟真实业务场景，5%的已到期订单仍保持未结清状态
                order.setStatus("已结清");
                order.setSettleDate(orderDueDate);
                order.setRemainPayAmount(BigDecimal.ZERO);
            } else {
                // 订单未到期，设置为未结清
                order.setStatus("未结清");
                order.setSettleDate(null);
                // 计算剩余金额（简化计算）
                long remainingMonths = orderDueDate.toEpochDay() - now.toEpochDay();
                remainingMonths = Math.max(0, remainingMonths / 30);
                order.setRemainPayAmount(loanAmount.multiply(BigDecimal.valueOf(remainingMonths))
                        .divide(BigDecimal.valueOf(term), 2, RoundingMode.HALF_UP));
            }
        }

        return order;
    }

    /**
     * 生成客户还款计划
     */
    public static List<CustomerRepayPlan> generateRepayPlan(CustomerOrder order, int monthlyOrders, int orderIndex) {
        List<CustomerRepayPlan> plans = new ArrayList<>();

        String loanTerm = order.getLoanTerm();
        int term = Integer.parseInt(loanTerm.replace("月", ""));
        BigDecimal loanAmount = order.getLoanAmount();
        String rateStr = order.getProductRate();
        double rate = Double.parseDouble(rateStr.replace("%", "")) / 100.0;
        String repayType = order.getRepayType();

        LocalDate loanDate = LocalDate.parse(order.getFrTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        LocalDate now = LocalDate.now();
        LocalDate now = LocalDate.of(2025, 9, 30);

        for (int i = 1; i <= term; i++) {
            CustomerRepayPlan plan = new CustomerRepayPlan();

            plan.setOrderNo(order.getOrderNo());
            plan.setBillId(order.getOrderNo() + "_" + String.format("%03d", i));
            plan.setLoanAmount(loanAmount);
            plan.setLoanTerm(loanTerm);
            plan.setBillTenor((long) i);
            plan.setRate(BigDecimal.valueOf(rate));
            plan.setMonthRate(BigDecimal.valueOf(rate / 12));

            // 应还款日期
            LocalDate dueDate = loanDate.plusMonths(i);
            plan.setDueDate(dueDate);

            // 计算本期应还金额
            calculateRepayAmount(plan, loanAmount, rate, term, repayType, i);

            // 初始状态设置
            plan.setRepayStatus("未到期");
            plan.setActualRepayDate(null);
            plan.setActualRepayMoney(BigDecimal.ZERO);
            plan.setOverdueDays(0);
            plan.setPenaltyInterest(BigDecimal.ZERO);

            plans.add(plan);
        }

        // 应用Vintage和迁徙率逻辑
        applyVintageMigrationLogic(plans, order, now, monthlyOrders, orderIndex);

        // 更新订单状态和剩余金额
        updateOrderStatusAndRemainAmount(order, plans, now);

        return plans;
    }

    /**
     * 计算本期应还金额
     */
    private static void calculateRepayAmount(CustomerRepayPlan plan, BigDecimal loanAmount,
                                             double rate, int term, String repayType, int currentTerm) {
        BigDecimal monthlyRate = BigDecimal.valueOf(rate / 12);

        switch (repayType) {
            case "等额本息":
                // 等额本息计算
                BigDecimal monthlyPayment = loanAmount.multiply(monthlyRate)
                        .multiply(BigDecimal.ONE.add(monthlyRate).pow(term))
                        .divide(BigDecimal.ONE.add(monthlyRate).pow(term).subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP);

                BigDecimal remainingPrincipal = loanAmount;
                for (int i = 1; i < currentTerm; i++) {
                    BigDecimal interest = remainingPrincipal.multiply(monthlyRate);
                    BigDecimal principal = monthlyPayment.subtract(interest);
                    remainingPrincipal = remainingPrincipal.subtract(principal);
                }

                BigDecimal currentInterest = remainingPrincipal.multiply(monthlyRate);
                BigDecimal currentPrincipal = monthlyPayment.subtract(currentInterest);

                plan.setNowPayPrincipal(currentPrincipal);
                plan.setNowPayInterest(currentInterest);
                plan.setNowPayAmount(monthlyPayment);
                break;

            case "等额本金":
                // 等额本金计算
                BigDecimal monthlyPrincipal = loanAmount.divide(BigDecimal.valueOf(term), 2, RoundingMode.HALF_UP);
                BigDecimal remainingPrincipal2 = loanAmount.subtract(monthlyPrincipal.multiply(BigDecimal.valueOf(currentTerm - 1)));
                BigDecimal currentInterest2 = remainingPrincipal2.multiply(monthlyRate);

                plan.setNowPayPrincipal(monthlyPrincipal);
                plan.setNowPayInterest(currentInterest2);
                plan.setNowPayAmount(monthlyPrincipal.add(currentInterest2));
                break;

//            case "先息后本":
//                // 先息后本计算
//                if (currentTerm == term) {
//                    plan.setNowPayPrincipal(loanAmount);
//                    plan.setNowPayInterest(BigDecimal.ZERO);
//                    plan.setNowPayAmount(loanAmount);
//                } else {
//                    BigDecimal interest = loanAmount.multiply(monthlyRate);
//                    plan.setNowPayPrincipal(BigDecimal.ZERO);
//                    plan.setNowPayInterest(interest);
//                    plan.setNowPayAmount(interest);
//                }
//                break;
        }
    }


    /**
     * 计算每月还款金额
     * 公式：每月偿还本息=〔贷款本金×月利率×(1＋月利率)＾还款月数〕÷〔(1＋月利率)＾还款月数-1〕
     *
     * @param loanAmount  贷款金额
     * @param annualRate  年利率
     * @param totalMonths 还款总月数
     * @return 每月还款金额
     */
    public static BigDecimal calculateMonthlyPayment(BigDecimal loanAmount, BigDecimal annualRate, int totalMonths) {
        BigDecimal monthlyRate = annualRate.divide(BigDecimal.valueOf(12), 10, RoundingMode.HALF_UP);
        //本金x月利率X(1+月利率)^n
        BigDecimal numerator = loanAmount.multiply(monthlyRate).multiply((BigDecimal.ONE.add(monthlyRate)).pow(totalMonths));
        //(1+月利率)^n -1
        BigDecimal denominator = (BigDecimal.ONE.add(monthlyRate))
                .pow(totalMonths)
                .subtract(BigDecimal.ONE);
        return numerator.divide(denominator, 4, RoundingMode.HALF_UP);
    }

    /**
     * 生成脱敏姓名
     */
    public static String generateMaskedName() {
        String[] surnames = {
                "王", "李", "张", "刘", "陈", "杨", "赵", "黄", "周", "吴", "徐", "孙", "胡", "朱", "高", "林", "何", "郭", "马", "罗",
                "梁", "宋", "郑", "谢", "韩", "唐", "冯", "于", "董", "萧", "程", "曹", "袁", "邓", "许", "傅", "沈", "曾", "彭", "吕",
                "苏", "卢", "蒋", "蔡", "贾", "丁", "魏", "薛", "叶", "余", "潘", "杜", "戴", "夏", "钟", "汪", "田", "任", "姜",
                "范", "方", "石", "姚", "谭", "廖", "邹", "熊", "金", "陆", "郝", "孔", "白", "崔", "康", "毛", "邱", "秦", "江", "史",
                "顾", "侯", "邵", "孟", "龙", "万", "段", "钱", "汤", "尹", "黎", "易", "常", "武", "乔", "贺", "赖", "龚", "文",
                "庞", "樊", "兰", "殷", "施", "陶", "洪", "翟", "安", "颜", "倪", "严", "牛", "温", "芦", "季", "俞", "章", "鲁", "葛",
                "伍", "韦", "申", "尤", "毕", "聂", "丛", "焦", "向", "柳", "邢", "路", "岳", "齐", "沿", "梅", "莫", "庄", "辛", "管",
                "祝", "左", "涂", "谷", "祁", "时", "舒", "耿", "牟", "卜", "路", "詹", "关", "苗", "凌", "费", "纪", "靳", "盛", "童",
                "欧", "项", "曲", "成", "游", "阳", "裴", "席", "卫", "查", "屈", "鲍", "位", "覃", "霍", "翁", "隋", "植", "甘",
                "景", "单", "包", "司", "柏", "宁", "柯", "阮", "桂", "闵", "梁", "宋", "郑",
                "谢", "韩", "唐", "冯", "于", "董", "萧", "程", "曹", "袁", "邓", "许", "傅", "沈", "曾", "彭", "吕", "苏", "卢", "蒋",
                "蔡", "贾", "丁", "魏", "薛", "叶", "阎", "余", "潘", "杜", "戴", "夏", "钟", "汪", "田", "任", "姜", "范", "方", "石",
                "姚", "谭", "廖", "邹", "熊", "金", "陆", "郝", "孔", "白", "崔", "康", "毛", "邱", "秦", "江", "史", "顾", "侯", "邵",
                "孟", "龙", "万", "段", "钱", "汤", "尹", "黎", "易", "常", "武", "乔", "贺", "赖", "龚", "文", "庞", "樊", "兰",
                "殷", "施", "陶", "洪", "翟", "安", "颜", "倪", "严", "牛", "温", "芦", "季", "俞", "章", "鲁", "葛", "伍", "韦", "申",
                "尤", "毕", "聂", "丛", "焦", "向", "邢", "路", "岳", "齐", "莫", "庄", "辛", "管", "祝", "左", "涂",
                "谷", "祁", "时", "舒", "耿", "牟", "卜", "路", "詹", "关", "苗", "凌", "费", "纪", "靳", "盛", "童", "欧", "项",
                "席", "卫", "查", "屈", "鲍", "位", "覃", "霍", "翁", "隋", "植", "甘", "景", "薄", "单", "宁", "柯", "阮"
        };

        String surname = surnames[random.nextInt(surnames.length)];

        // 脱敏格式：徐** 或 欧阳**
        return surname + "**";
    }

    /**
     * 应用Vintage和迁徙率逻辑到还款计划
     */
    private static void applyVintageMigrationLogic(List<CustomerRepayPlan> plans, CustomerOrder order, LocalDate now, int monthlyOrders, int orderIndex) {
        if (plans.isEmpty()) return;
        LocalDate processingCutoffDate = LocalDate.of(2025, 9, 30);
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
        LocalDate beforeDueDate = null;

        // 如果订单状态是已结清，则所有还款计划都标记为已结清
        if ("已结清".equals(order.getStatus())) {
            LocalDate settleDate = order.getSettleDate();
            if (settleDate != null) {
                
                for (CustomerRepayPlan plan : plans) {
                    LocalDate dueDate = plan.getDueDate();

                        if (dueDate.isBefore(settleDate)) {
                            // dueDate < settleDate：正常还款，实际还款金额等于应还金额
                            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;
                            plan.setRepayStatus("已结清");
                            long overdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();

                            // 计算罚息
                        if (overdueDays > 3) {
                            BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal("1.5"));
                            BigDecimal penaltyInterest = plan.getNowPayAmount()
                                    .multiply(penaltyRate)
                                    .multiply(BigDecimal.valueOf(overdueDays))
                                    .setScale(2, RoundingMode.HALF_UP);
                            plan.setPenaltyInterest(penaltyInterest);
                        } else {
                            plan.setPenaltyInterest(BigDecimal.ZERO);
                        }
                        plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(actualRepayDate);
                        plan.setActualRepayMoney(plan.getNowPayAmount());
                        plan.setActualPrincipal(plan.getNowPayPrincipal());
                        plan.setActualInterest(plan.getNowPayInterest());
                        plan.setOverdueDays((int) overdueDays);
//                        plan.setPenaltyInterest(BigDecimal.ZERO);
                    } else if (dueDate.isEqual(settleDate)) {
                        // dueDate == settleDate：提前结清，实际还款本金等于剩余期数应还本金之和
                        LocalDate actualRepayDate = settleDate.isAfter(maxRepayDate) ? maxRepayDate : settleDate;
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(actualRepayDate);

                        // 计算剩余期数应还本金之和
                        BigDecimal totalRemainingPrincipal = BigDecimal.ZERO;
                        int currentTerm = plan.getBillTenor().intValue();
                        int totalTerms = Integer.parseInt(order.getLoanTerm().replace("月", ""));

                        // 计算从当前期到最后一期的所有应还本金
                        for (int i = currentTerm; i <= totalTerms; i++) {
                            final int termIndex = i;
                            CustomerRepayPlan remainingPlan = plans.stream()
                                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                                    .findFirst()
                                    .orElse(null);

                            if (remainingPlan != null) {
                                totalRemainingPrincipal = totalRemainingPrincipal.add(remainingPlan.getNowPayPrincipal());
                            }
                        }

                        // 实际还款本金 = 剩余期数应还本金之和
                        plan.setActualPrincipal(totalRemainingPrincipal);
                        // 实际还款利息 = 本期的应还利息
                        plan.setActualInterest(plan.getNowPayInterest());
                        // 实际还款金额 = 实际还款本金 + 实际还款利息
                        plan.setActualRepayMoney(totalRemainingPrincipal.add(plan.getNowPayInterest()));
                        plan.setOverdueDays(0);
                        plan.setPenaltyInterest(BigDecimal.ZERO);

                        // 将剩余期数的还款计划也标记为已结清，实还金额为0
                        for (int i = currentTerm + 1; i <= totalTerms; i++) {
                            final int termIndex = i;
                            CustomerRepayPlan remainingPlan = plans.stream()
                                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                                    .findFirst()
                                    .orElse(null);

                            if (remainingPlan != null) {
                                remainingPlan.setRepayStatus("已结清");
                                remainingPlan.setActualRepayDate(actualRepayDate);
                                remainingPlan.setActualRepayMoney(BigDecimal.ZERO);
                                remainingPlan.setActualPrincipal(BigDecimal.ZERO);
                                remainingPlan.setActualInterest(BigDecimal.ZERO);
                                remainingPlan.setOverdueDays(0);
                                remainingPlan.setPenaltyInterest(BigDecimal.ZERO);
                            }
                        }
                    } else {
                        // dueDate > settleDate的期数也标记为已结清，但实还金额为0
                        LocalDate actualRepayDate = settleDate.isAfter(maxRepayDate) ? maxRepayDate : settleDate;
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(actualRepayDate);
                        plan.setActualRepayMoney(BigDecimal.ZERO);
                        plan.setActualPrincipal(BigDecimal.ZERO);
                        plan.setActualInterest(BigDecimal.ZERO);
                        plan.setOverdueDays(0);
                        plan.setPenaltyInterest(BigDecimal.ZERO);
                    }
                }
            }
            return; // 订单已结清，直接返回
        } if ("逾期".equals(order.getStatus())) {// 如果订单状态是逾期 这里需要为term做递增增长，这边要关联
            int randomPercent = random.nextInt(100);
            boolean shouldProcessSpecialLogic = randomPercent < 99;//80还了三期之后逾期
            int randomNumbe = random.nextInt(10);//前10期还款后再逾期
            int randomterm = random.nextInt(2);//如果就是三期账单的话则前两期还款后逾期

            for (CustomerRepayPlan plan : plans) {
                LocalDate dueDate = plan.getDueDate();
                Long billTenor = plan.getBillTenor();
                if (dueDate.isBefore(processingCutoffDate)) {
                    long overdueDays = maxRepayDate.toEpochDay() - dueDate.toEpochDay();
                    if (shouldProcessSpecialLogic) {//正常还款期数
                        if (plans.size() == 3) {
                            // 如果是3期账单，前randomterm期正常还款，之后逾期
                            if (billTenor <= randomterm) {
                                // 前randomterm期正常还款
                                plan.setRepayStatus("已结清");
                                plan.setActualRepayDate(dueDate);
                                plan.setActualPrincipal(plan.getNowPayPrincipal());
                                plan.setActualInterest(plan.getNowPayInterest());
                                plan.setActualRepayMoney(plan.getNowPayAmount());
                                plan.setPenaltyInterest(BigDecimal.ZERO);
                                plan.setOverdueDays(0);
                            } else {
                                // 之后的期数逾期
                                // 计算罚息
                                if (overdueDays > 3) {
                                    BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                            .multiply(new BigDecimal("1.5"));
                                    BigDecimal penaltyInterest = plan.getNowPayAmount()
                                            .multiply(penaltyRate)
                                            .multiply(BigDecimal.valueOf(overdueDays))
                                            .setScale(2, RoundingMode.HALF_UP);
                                    plan.setPenaltyInterest(penaltyInterest);
                                } else {
                                    plan.setPenaltyInterest(BigDecimal.ZERO);
                                }
                                plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                                plan.setRepayStatus("逾期");
                                plan.setOverdueDays((int) overdueDays);
                            }
                        }else if (plans.size() == 6) {//兼容6期产品
                            // 如果是3期账单，前randomterm期正常还款，之后逾期
                            if (billTenor <= 4) {
                                // 前randomterm期正常还款
                                plan.setRepayStatus("已结清");
                                plan.setActualRepayDate(dueDate);
                                plan.setActualPrincipal(plan.getNowPayPrincipal());
                                plan.setActualInterest(plan.getNowPayInterest());
                                plan.setActualRepayMoney(plan.getNowPayAmount());
                                plan.setPenaltyInterest(BigDecimal.ZERO);
                                plan.setOverdueDays(0);
                            } else {
                                // 之后的期数逾期
                                // 计算罚息
                                if (overdueDays > 3) {
                                    BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                            .multiply(new BigDecimal("1.5"));
                                    BigDecimal penaltyInterest = plan.getNowPayAmount()
                                            .multiply(penaltyRate)
                                            .multiply(BigDecimal.valueOf(overdueDays))
                                            .setScale(2, RoundingMode.HALF_UP);
                                    plan.setPenaltyInterest(penaltyInterest);
                                } else {
                                    plan.setPenaltyInterest(BigDecimal.ZERO);
                                }
                                plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                                plan.setRepayStatus("逾期");
                                plan.setOverdueDays((int) overdueDays);
                            }
                        } else {
                            // 如果不是3期账单，前randomNumbe期正常还款，之后逾期
                            if (billTenor <= randomNumbe) {
                                // 前randomNumbe期正常还款
                                plan.setRepayStatus("已结清");
                                plan.setActualRepayDate(dueDate);
                                plan.setActualPrincipal(plan.getNowPayPrincipal());
                                plan.setActualInterest(plan.getNowPayInterest());
                                plan.setActualRepayMoney(plan.getNowPayAmount());
                                plan.setPenaltyInterest(BigDecimal.ZERO);
                                plan.setOverdueDays(0);
                            } else {
                                // 之后的期数逾期
                                // 计算罚息
                                if (overdueDays > 3) {
                                    BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                            .multiply(new BigDecimal("1.5"));
                                    BigDecimal penaltyInterest = plan.getNowPayAmount()
                                            .multiply(penaltyRate)
                                            .multiply(BigDecimal.valueOf(overdueDays))
                                            .setScale(2, RoundingMode.HALF_UP);
                                    plan.setPenaltyInterest(penaltyInterest);
                                } else {
                                    plan.setPenaltyInterest(BigDecimal.ZERO);
                                }
                                plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                                plan.setRepayStatus("逾期");
                                plan.setOverdueDays((int) overdueDays);
                            }
                        }

                    } else {
                        // 计算罚息
                        if (overdueDays > 3) {
                            BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal("1.5"));
                            BigDecimal penaltyInterest = plan.getNowPayAmount()
                                    .multiply(penaltyRate)
                                    .multiply(BigDecimal.valueOf(overdueDays))
                                    .setScale(2, RoundingMode.HALF_UP);
                            plan.setPenaltyInterest(penaltyInterest);
                        } else {
                            plan.setPenaltyInterest(BigDecimal.ZERO);
                        }
                        plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                        plan.setRepayStatus("逾期");
                        plan.setOverdueDays((int) overdueDays);
                    }

                } else {
                    // 未到期的计划
                    plan.setRepayStatus("未到期");
                    plan.setActualRepayDate(null);
                    plan.setActualRepayMoney(BigDecimal.ZERO);
                    plan.setOverdueDays(0);
                }
            }
            return; // 订单处理完，直接返回
        }else if ("逾期已还".equals(order.getStatus())) {
            int randomPercent = random.nextInt(100);
            boolean shouldProcessSpecialLogic = randomPercent < 80;
            boolean shouldProcessSpecia = randomPercent < 60;
            for (CustomerRepayPlan plan : plans) {
                LocalDate dueDate = plan.getDueDate();
                if (dueDate.isBefore(processingCutoffDate)) {
                    int overDays = 0;
                    if (shouldProcessSpecialLogic&&plan.getBillTenor() == 1L) {
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(dueDate);
                        plan.setActualRepayMoney(plan.getNowPayAmount());
                        plan.setActualPrincipal(plan.getNowPayPrincipal());
                        plan.setActualInterest(plan.getNowPayInterest());
                        plan.setOverdueDays(0);
                    } else if (shouldProcessSpecia&&plan.getBillTenor() == 2L) {
                        plan.setRepayStatus("已结清");
                        plan.setActualRepayDate(dueDate);
                        plan.setActualRepayMoney(plan.getNowPayAmount());
                        plan.setActualPrincipal(plan.getNowPayPrincipal());
                        plan.setActualInterest(plan.getNowPayInterest());
                        plan.setOverdueDays(0);
                    }else {
                        // 根据dueDate前两位（如"2023-07"）和期数1来分配逾期天数
                        String bucket = shouldOverdue();
                        overDays = calculateActualOverdueDays(bucket);
//                    }

                        LocalDate dueDay = dueDate.plusDays(overDays);
                        // 正常还款，确保实际还款日期小于等于2025-09-30
                        LocalDate actualRepayDate = dueDay.isAfter(maxRepayDate) ? maxRepayDate : dueDay;
                        // 上一期还款日，这一期的还款日要在上一期的后面
                        if (null != beforeDueDate && beforeDueDate.isAfter(dueDay)) {
                            // 如果上一期还款日期晚于当前期计算的还款日期，则使用上一期的还款日期
                            actualRepayDate = beforeDueDate.isAfter(maxRepayDate) ? maxRepayDate : beforeDueDate;
                        }
                        beforeDueDate = actualRepayDate;
                        long overdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
                        // 计算罚息
                        if (overdueDays > 3) {
                            BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                                    .multiply(new BigDecimal("1.5"));
                            BigDecimal penaltyInterest = plan.getNowPayAmount()
                                    .multiply(penaltyRate)
                                    .multiply(BigDecimal.valueOf(overdueDays))
                                    .setScale(2, RoundingMode.HALF_UP);
                            plan.setPenaltyInterest(penaltyInterest);
                        } else {
                            plan.setPenaltyInterest(BigDecimal.ZERO);
                        }
                        plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
                        plan.setRepayStatus("已结清");
                        plan.setOverdueDays((int) overdueDays);
                        plan.setActualRepayDate(actualRepayDate);
                        plan.setActualRepayMoney(plan.getNowPayAmount());
                        plan.setActualPrincipal(plan.getNowPayPrincipal());
                        plan.setActualInterest(plan.getNowPayInterest());
                    }

                } else {
                    // 未到期的计划
                    plan.setRepayStatus("未到期");
                    plan.setActualRepayDate(null);
                    plan.setActualRepayMoney(BigDecimal.ZERO);
                    plan.setOverdueDays(0);
                }
            }
            return; // 订单已结清，直接返回
        }else {
            // 为每个还款计划应用逾期逻辑
            for (CustomerRepayPlan plan : plans) {
                LocalDate dueDate = plan.getDueDate();

                // 2025-10-01及以后的数据都标记为未到期
                if (dueDate.isAfter(processingCutoffDate) || dueDate.isEqual(processingCutoffDate)) {
                    plan.setRepayStatus("未到期");
                    plan.setActualRepayDate(null);
                    plan.setActualRepayMoney(BigDecimal.ZERO);
                    plan.setOverdueDays(0);
                    continue;
                }

                // 处理2025-09-30之前的数据
                if (dueDate.isBefore(processingCutoffDate)) {
                    plan.setRepayStatus("已结清");
                    plan.setActualRepayDate(dueDate);
                    plan.setActualRepayMoney(plan.getNowPayAmount());
                    plan.setOverdueDays(0);
                    plan.setActualPrincipal(plan.getNowPayPrincipal());
                    plan.setActualInterest(plan.getNowPayInterest());
                    plan.setPenaltyInterest(BigDecimal.ZERO);
                }
            }
        }
    }

    /**
     * 选择逾期区间，确保每个月都有逾期状态和逾期还款记录
     * 逾期天数分布：1-7天，7-15天，15-30天，30-60天，每隔30天递增到820天
     * 第一期逾期天数分布：1-7天，7-15天，15-30天，30-60天，每隔30天递增到360天
     * 概率递减：1-7天5%，7-15天3%，15-30天2%，30-60天1.5%，60-90天1.2%，90-120天1%...
     */
    private static String selectOverdueBucketWithMonthlyDistribution(String frTime, LocalDate dueDate, int period) {
        // 根据放款时间和dueDate生成均匀分布的随机数，确保每个月都有逾期数据
        double bucketRandom = generateUniformRandomFromFrTimeDueDateAndPeriod(frTime, dueDate, period);

        // 总逾期比例：确保每个月都有逾期数据
        double totalOverdueRate = 0.15; // 15%的逾期率，确保每个月都有逾期数据

        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < totalOverdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / totalOverdueRate); // 重新映射到0-1范围

            if (period == 1) {
                // 第一期：逾期天数分布到360天，概率递减
                if (overdueRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
                else if (overdueRandom < 0.08) return "M7_15"; // 3% -> 逾期7-15天
                else if (overdueRandom < 0.10) return "M15_30"; // 2% -> 逾期15-30天
                else if (overdueRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
                else if (overdueRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
                else if (overdueRandom < 0.137) return "M90_120"; // 1% -> 逾期90-120天
                else if (overdueRandom < 0.145) return "M120_150"; // 0.8% -> 逾期120-150天
                else if (overdueRandom < 0.152) return "M150_180"; // 0.7% -> 逾期150-180天
                else if (overdueRandom < 0.158) return "M180_210"; // 0.6% -> 逾期180-210天
                else if (overdueRandom < 0.163) return "M210_240"; // 0.5% -> 逾期210-240天
                else if (overdueRandom < 0.167) return "M240_270"; // 0.4% -> 逾期240-270天
                else if (overdueRandom < 0.170) return "M270_300"; // 0.3% -> 逾期270-300天
                else if (overdueRandom < 0.172) return "M300_330"; // 0.2% -> 逾期300-330天
                else if (overdueRandom < 0.174) return "M330_360"; // 0.2% -> 逾期330-360天
                else return "NORMAL"; // 正常还款
            } else {
                // 非第一期：逾期天数分布到820天，概率递减
                if (overdueRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
                else if (overdueRandom < 0.08) return "M7_15"; // 3% -> 逾期7-15天
                else if (overdueRandom < 0.10) return "M15_30"; // 2% -> 逾期15-30天
                else if (overdueRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
                else if (overdueRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
                else if (overdueRandom < 0.137) return "M90_120"; // 1% -> 逾期90-120天
                else if (overdueRandom < 0.145) return "M120_150"; // 0.8% -> 逾期120-150天
                else if (overdueRandom < 0.152) return "M150_180"; // 0.7% -> 逾期150-180天
                else if (overdueRandom < 0.158) return "M180_210"; // 0.6% -> 逾期180-210天
                else if (overdueRandom < 0.163) return "M210_240"; // 0.5% -> 逾期210-240天
                else if (overdueRandom < 0.167) return "M240_270"; // 0.4% -> 逾期240-270天
                else if (overdueRandom < 0.170) return "M270_300"; // 0.3% -> 逾期270-300天
                else if (overdueRandom < 0.172) return "M300_330"; // 0.2% -> 逾期300-330天
                else if (overdueRandom < 0.174) return "M330_360"; // 0.2% -> 逾期330-360天
                else if (overdueRandom < 0.176) return "M360_390"; // 0.2% -> 逾期360-390天
                else if (overdueRandom < 0.178) return "M390_420"; // 0.2% -> 逾期390-420天
                else if (overdueRandom < 0.180) return "M420_450"; // 0.2% -> 逾期420-450天
                else if (overdueRandom < 0.182) return "M450_480"; // 0.2% -> 逾期450-480天
                else if (overdueRandom < 0.184) return "M480_510"; // 0.2% -> 逾期480-510天
                else if (overdueRandom < 0.186) return "M510_540"; // 0.2% -> 逾期510-540天
                else if (overdueRandom < 0.188) return "M540_570"; // 0.2% -> 逾期540-570天
                else if (overdueRandom < 0.190) return "M570_600"; // 0.2% -> 逾期570-600天
                else if (overdueRandom < 0.192) return "M600_630"; // 0.2% -> 逾期600-630天
                else if (overdueRandom < 0.194) return "M630_660"; // 0.2% -> 逾期630-660天
                else if (overdueRandom < 0.196) return "M660_690"; // 0.2% -> 逾期660-690天
                else if (overdueRandom < 0.198) return "M690_720"; // 0.2% -> 逾期690-720天
                else if (overdueRandom < 0.200) return "M720_750"; // 0.2% -> 逾期720-750天
                else if (overdueRandom < 0.202) return "M750_780"; // 0.2% -> 逾期750-780天
                else if (overdueRandom < 0.204) return "M780_810"; // 0.2% -> 逾期780-810天
                else if (overdueRandom < 0.206) return "M810_820"; // 0.2% -> 逾期810-820天
                else return "NORMAL"; // 正常还款
            }
        } else {
            return "NORMAL"; // 正常还款
        }
    }

    /**
     * 应用逾期逻辑，支持新的逾期天数分布
     */
    private static void applyOverdueLogicWithMonthlyDistribution(CustomerRepayPlan plan, CustomerOrder order,
                                                                 LocalDate dueDate, LocalDate now, String overdueBucket,
                                                                 List<CustomerRepayPlan> allPlans) {
        // 计算实际还款日期
        LocalDate actualRepayDate = calculateActualRepayDateByMonthlyDistribution(dueDate, overdueBucket);

        // 确保实际还款日期在2025-09-30之前
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }

        // 计算逾期天数
        long overdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();

        // 设置还款状态为已结清（逾期后还款）
        plan.setRepayStatus("已结清");
        plan.setActualRepayDate(actualRepayDate);
        plan.setActualRepayMoney(plan.getNowPayAmount());
        plan.setOverdueDays((int) overdueDays);
        plan.setActualPrincipal(plan.getNowPayPrincipal());
        plan.setActualInterest(plan.getNowPayInterest());

        // 计算罚息
        if (overdueDays > 3) {
            BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("1.5"));
            BigDecimal penaltyInterest = plan.getNowPayAmount()
                    .multiply(penaltyRate)
                    .multiply(BigDecimal.valueOf(overdueDays))
                    .setScale(2, RoundingMode.HALF_UP);
            plan.setPenaltyInterest(penaltyInterest);
        } else {
            plan.setPenaltyInterest(BigDecimal.ZERO);
        }
    }

    /**
     * 根据新的逾期天数分布计算实际还款日期
     */
    private static LocalDate calculateActualRepayDateByMonthlyDistribution(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);

        switch (overdueBucket) {
            case "M1_7":
                return dueDate.plusDays(1 + random.nextInt(7)); // 1-7天
            case "M7_15":
                return dueDate.plusDays(7 + random.nextInt(9)); // 7-15天
            case "M15_30":
                return dueDate.plusDays(15 + random.nextInt(16)); // 15-30天
            case "M30_60":
                return dueDate.plusDays(30 + random.nextInt(31)); // 30-60天
            case "M60_90":
                return dueDate.plusDays(60 + random.nextInt(31)); // 60-90天
            case "M90_120":
                return dueDate.plusDays(90 + random.nextInt(31)); // 90-120天
            case "M120_150":
                return dueDate.plusDays(120 + random.nextInt(31)); // 120-150天
            case "M150_180":
                return dueDate.plusDays(150 + random.nextInt(31)); // 150-180天
            case "M180_210":
                return dueDate.plusDays(180 + random.nextInt(31)); // 180-210天
            case "M210_240":
                return dueDate.plusDays(210 + random.nextInt(31)); // 210-240天
            case "M240_270":
                return dueDate.plusDays(240 + random.nextInt(31)); // 240-270天
            case "M270_300":
                return dueDate.plusDays(270 + random.nextInt(31)); // 270-300天
            case "M300_330":
                return dueDate.plusDays(300 + random.nextInt(31)); // 300-330天
            case "M330_360":
                return dueDate.plusDays(330 + random.nextInt(31)); // 330-360天
            case "M360_390":
                return dueDate.plusDays(360 + random.nextInt(31)); // 360-390天
            case "M390_420":
                return dueDate.plusDays(390 + random.nextInt(31)); // 390-420天
            case "M420_450":
                return dueDate.plusDays(420 + random.nextInt(31)); // 420-450天
            case "M450_480":
                return dueDate.plusDays(450 + random.nextInt(31)); // 450-480天
            case "M480_510":
                return dueDate.plusDays(480 + random.nextInt(31)); // 480-510天
            case "M510_540":
                return dueDate.plusDays(510 + random.nextInt(31)); // 510-540天
            case "M540_570":
                return dueDate.plusDays(540 + random.nextInt(31)); // 540-570天
            case "M570_600":
                return dueDate.plusDays(570 + random.nextInt(31)); // 570-600天
            case "M600_630":
                return dueDate.plusDays(600 + random.nextInt(31)); // 600-630天
            case "M630_660":
                return dueDate.plusDays(630 + random.nextInt(31)); // 630-660天
            case "M660_690":
                return dueDate.plusDays(660 + random.nextInt(31)); // 660-690天
            case "M690_720":
                return dueDate.plusDays(690 + random.nextInt(31)); // 690-720天
            case "M720_750":
                return dueDate.plusDays(720 + random.nextInt(31)); // 720-750天
            case "M750_780":
                return dueDate.plusDays(750 + random.nextInt(31)); // 750-780天
            case "M780_810":
                return dueDate.plusDays(780 + random.nextInt(31)); // 780-810天
            case "M810_820":
                return dueDate.plusDays(810 + random.nextInt(11)); // 810-820天
            default:
                return dueDate; // 正常还款
        }
    }

    /**
     * 生成正态分布的年龄
     */
    public static int generateNormalDistributedAge() {
        double rand = random.nextDouble();

        // 根据分布比例生成年龄
        if (rand < 0.01) { // 18-20（1%）
            return 18 + random.nextInt(3);
        } else if (rand < 0.06) { // 20-25（5%）
            return 20 + random.nextInt(6);
        } else if (rand < 0.16) { // 25-30（10%）
            return 25 + random.nextInt(6);
        } else if (rand < 0.51) { // 30-35（35%）
            return 30 + random.nextInt(6);
        } else if (rand < 0.76) { // 35-40（25%）
            return 35 + random.nextInt(6);
        } else if (rand < 0.91) { // 40-45（15%）
            return 40 + random.nextInt(6);
        } else if (rand < 0.97) { // 45-50（6%）
            return 45 + random.nextInt(6);
        } else if (rand < 1.00) { // 50-55（3%）
            return 50 + random.nextInt(6);
        } else { // 55以上（1%）
            return 55 + random.nextInt(10);
        }
    }

    /**
     * 生成该月内随机的一天
     */
    private static LocalDate generateRandomDayInMonth(LocalDate month) {
        // 获取该月的第一天和最后一天
        LocalDate firstDay = month.withDayOfMonth(1);
        LocalDate lastDay = month.withDayOfMonth(month.lengthOfMonth());

        // 计算该月的天数
        int daysInMonth = month.lengthOfMonth();

        // 生成随机天数（1到该月天数）
        int randomDay = 1 + random.nextInt(daysInMonth);

        return firstDay.withDayOfMonth(randomDay);
    }

    /**
     * 根据期数计算逾期率（基于真实业务数据的波状图模式，降低逾期率）
     * 在逾逾期比例按3月、6月、12月平均分配
     */
    private static double calculatePeriodOverdueRate(int period, String loanTerm) {
        // 第一期已经通过selectFirstPeriodOverdueBucket处理，这里只处理非第一期
        // 为了保持整体逾期率不变，需要调整非第一期的逾期率

        // 根据贷款期限调整逾期率，平均分配在逾逾期比例
        double baseRate;
        if ("3月".equals(loanTerm)) {
            // 3月贷款：平均分配在逾逾期比例
            baseRate = 0.00015; // 3月贷款的基础逾期率
        } else if ("6月".equals(loanTerm)) {
            // 6月贷款：平均分配在逾逾期比例
            baseRate = 0.00015; // 6月贷款的基础逾期率
        } else if ("12月".equals(loanTerm)) {
            // 12月贷款：平均分配在逾逾期比例
            baseRate = 0.00015; // 12月贷款的基础逾期率
        } else {
            // 其他期限保持原有逻辑
            baseRate = FIRST_PERIOD_OVERDUE_RATE * 0.5;
        }

        if (period == 1) {
            // 第一期不在这里处理，返回0
            return 0.0;
        } else if (period <= 2) {
            return baseRate * 1.5;
        } else if (period <= 10) {
            // 从第2期到第10期逐渐增加到峰值
            double progress = (period - 2.0) / 8.0; // 0到1的进度
            return baseRate * 1.5 + (baseRate * 10 - baseRate * 1.5) * progress;
        } else {
            // 从第10期开始逐渐下降
            double progress = Math.min((period - 10.0) / 14.0, 1.0); // 0到1的进度，最多到第24期
            return baseRate * 10 - (baseRate * 10 - baseRate * 1.5) * progress;
        }
    }

    /**
     * 选择逾期区间（按指定比例分布）
     */
    private static String selectOverdueBucket() {
        double bucketRandom = random.nextDouble();
        if (bucketRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
        else if (bucketRandom < 0.08) return "M8_15"; // 3% -> 逾期8-15天
        else if (bucketRandom < 0.10) return "M16_30"; // 2% -> 逾期16-30天
        else if (bucketRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
        else if (bucketRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
        else if (bucketRandom < 0.137) return "M90_180"; // 1% -> 逾期90天以上
        else return "NORMAL"; // 正常还款（86.3%）
    }

    /**
     * 选择第一期逾期区间（按指定比例分布，保证整体逾期率不变）
     * 每个月都要有逾期未还的订单，并且比例差不多
     */
    private static String selectFirstPeriodOverdueBucket() {
        double bucketRandom = random.nextDouble();
        if (bucketRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
        else if (bucketRandom < 0.08) return "M8_15"; // 3% -> 逾期8-15天
        else if (bucketRandom < 0.10) return "M16_30"; // 2% -> 逾期16-30天
        else if (bucketRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
        else if (bucketRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
        else if (bucketRandom < 0.137) return "M90_180"; // 1% -> 逾期90天以上
        else return "NORMAL"; // 正常还款（86.3%）
    }

    /**
     * 选择第一期逾期区间（确保每个月都有逾期未还的订单）
     * 使用基于订单号的哈希值来确保每个月都有逾期订单
     */
    private static String selectFirstPeriodOverdueBucketWithGuarantee(CustomerOrder order) {
        // 使用订单号生成一个稳定的随机数，确保每个月都有逾期订单
        long orderHash = Math.abs(order.getOrderNo().hashCode());
        double bucketRandom = (orderHash % 10000) / 10000.0; // 0-1之间的稳定值

        if (bucketRandom < 0.05) return "M1_7";     // 5% -> 逾期1-7天
        else if (bucketRandom < 0.08) return "M8_15"; // 3% -> 逾期8-15天
        else if (bucketRandom < 0.10) return "M16_30"; // 2% -> 逾期16-30天
        else if (bucketRandom < 0.115) return "M30_60"; // 1.5% -> 逾期30-60天
        else if (bucketRandom < 0.127) return "M60_90"; // 1.2% -> 逾期60-90天
        else if (bucketRandom < 0.137) return "M90_180"; // 1% -> 逾期90天以上
        else return "NORMAL"; // 正常还款（86.3%）
    }

    /**
     * 根据贷款期限选择逾期区间，确保3月、6月、12月贷款的逾期数量基本相等
     * 每个月都有逾期和逾期已还的记录
     */
    private static String selectOverdueBucketByLoanTerm(String loanTerm, String orderNo) {
        // 使用订单号生成一个稳定的随机数，确保每个月都有逾期订单
        long orderHash = Math.abs(orderNo.hashCode());
        double bucketRandom = (orderHash % 10000) / 10000.0; // 0-1之间的稳定值

        // 根据贷款期限调整逾期比例，确保3月、6月、12月逾期数量基本相等
        double overdueRate;
        if ("3月".equals(loanTerm)) {
            overdueRate = 0.15; // 3月贷款15%逾期率
        } else if ("6月".equals(loanTerm)) {
            overdueRate = 0.15; // 6月贷款15%逾期率
        } else if ("12月".equals(loanTerm)) {
            overdueRate = 0.15; // 12月贷款15%逾期率
        } else {
            overdueRate = 0.10; // 其他期限10%逾期率
        }

        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < overdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / overdueRate); // 重新映射到0-1范围

            if (overdueRandom < 0.33) return "M1_7";     // 33% -> 逾期1-7天
            else if (overdueRandom < 0.55) return "M8_15"; // 22% -> 逾期8-15天
            else if (overdueRandom < 0.70) return "M16_30"; // 15% -> 逾期16-30天
            else if (overdueRandom < 0.82) return "M30_60"; // 12% -> 逾期30-60天
            else if (overdueRandom < 0.90) return "M60_90"; // 8% -> 逾期60-90天
            else return "M90_180"; // 10% -> 逾期90天以上
        } else {
            return "NORMAL"; // 正常还款
        }
    }

    /**
     * 选择逾期区间，总逾期比例5%，确保每个月都有逾期记录
     * 逾期已还的天数分布：1-7天、7-15天、15-30天、30-60天、60-90天
     */
    private static String selectOverdueBucketWith5PercentRate(String orderNo) {
        // 使用订单号生成一个稳定的随机数，确保每个月都有逾期订单
        long orderHash = Math.abs(orderNo.hashCode());
        double bucketRandom = (orderHash % 10000) / 10000.0; // 0-1之间的稳定值

        // 总逾期比例5%
        double overdueRate = 0.05;

        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < overdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / overdueRate); // 重新映射到0-1范围

            if (overdueRandom < 0.20) return "M1_7";     // 20% -> 逾期1-7天
            else if (overdueRandom < 0.40) return "M7_15"; // 20% -> 逾期7-15天
            else if (overdueRandom < 0.60) return "M15_30"; // 20% -> 逾期15-30天
            else if (overdueRandom < 0.80) return "M30_60"; // 20% -> 逾期30-60天
            else return "M60_90"; // 20% -> 逾期60-90天
        } else {
            return "NORMAL"; // 正常还款（50%）
        }
    }

    /**
     * 选择逾期区间，总逾期比例50%，详细逾期天数分布
     * 目标：10000个订单中生成5%的逾期超过400天的订单（即500个订单）
     * 在50%的逾期订单中，超过400天的比例应该是10%
     */
    private static String selectOverdueBucketWithDetailedDistribution(String frTime, LocalDate dueDate, int period) {
//        // 使用多种策略确保分布均匀，避免因订单号递增导致的分布不均
//        // 根据放款时间frTime生成均匀分布的随机数，确保每个月都有逾期数据
//        double bucketRandom = generateUniformRandomFromFrTimeAndPeriod(frTime, period);
//        根据放款时间frTime、dueDate和期数生成均匀分布的随机数，确保每个月都有逾期数据
        double bucketRandom = generateUniformRandomFromDueDateAndPeriod(dueDate, period);
        // 使用真正的随机数生成器，确保均匀分布
//        double bucketRandom = random.nextDouble(); // 0-1之间的真正随机值
        // 根据放款时间frTime和期数生成均匀分布的随机数，确保每个月都有逾期数据
//        double bucketRandom;
//        if (period == 1) {
//            // 第一期：根据dueDate的前两位（如"2023-09"）来分配逾期已还的比例
//            bucketRandom = generateUniformRandomFromDueDateAndPeriod(dueDate, period);
//        } else {
//            // 非第一期：根据放款时间frTime的前两位来分配
//            bucketRandom = generateUniformRandomFromFrTimeAndPeriod(frTime, period);
//        }

        // 总逾期比例26%
        double totalOverdueRate = 0.24;

        // 在逾期范围内按比例分配逾期区间
        if (bucketRandom < totalOverdueRate) {
            // 逾期后还款，按比例分配逾期区间
            double overdueRandom = (bucketRandom / totalOverdueRate); // 重新映射到0-1范围

//            if (period == 1) {
////                 第一期：提高400天以上逾期的比例到10%
////                if (overdueRandom < 0.6) return "M1_7";     // 15% -> 逾期1-7天
////                else if (overdueRandom < 0.85) return "M7_15"; // 10% -> 逾期7-15天
////                else if (overdueRandom < 0.90) return "M15_30"; // 10% -> 逾期15-30天
//                if (overdueRandom < 0.4) return "M30_60"; // 10% -> 逾期30-60天
//                else if (overdueRandom < 0.6) return "M60_90"; // 10% -> 逾期60-90天
//                else if (overdueRandom < 0.8) return "M90_120"; // 10% -> 逾期90-120天
//                else if (overdueRandom < 0.9) return "M120_150"; // 10% -> 逾期120-150天
//                else if (overdueRandom < 0.92) return "M150_180"; // 3% -> 逾期150-180天
//                else if (overdueRandom < 0.94) return "M180_210"; // 3% -> 逾期180-210天
//                else if (overdueRandom < 0.96) return "M210_240"; // 3% -> 逾期210-240天
//                else if (overdueRandom < 0.97) return "M240_270"; // 3% -> 逾期240-270天
//                else if (overdueRandom < 0.98) return "M270_300"; // 3% -> 逾期270-300天
//                else if (overdueRandom < 0.99) return "M300_330"; // 2% -> 逾期300-330天
//                else if (overdueRandom < 0.991) return "M330_360"; // 2% -> 逾期330-360天
//                else if (overdueRandom < 0.992) return "M360_390"; // 2% -> 逾期360-390天
//                else if (overdueRandom < 0.99) return "M390_420"; // 1% -> 逾期390-420天
//                else if (overdueRandom < 0.993) return "M420_450"; // 1% -> 逾期420-450天
//                else if (overdueRandom < 0.994) return "M450_480"; // 0.5% -> 逾期450-480天
//                else if (overdueRandom < 0.995) return "M480_510"; // 0.5% -> 逾期480-510天
//                else if (overdueRandom < 0.996) return "M510_540"; // 0.5% -> 逾期510-540天
//                else if (overdueRandom < 0.997) return "M540_570"; // 0.3% -> 逾期540-570天
//                else if (overdueRandom < 0.998) return "M570_600"; // 0.1% -> 逾期570-600天
//                else if (overdueRandom < 0.9985) return "M600_630"; // 0.05% -> 逾期600-630天
//                else if (overdueRandom < 0.9999) return "M630_660"; // 0.03% -> 逾期630-660天
//                else if (overdueRandom < 1.0) return "M660_690"; // 0.02% -> 逾期660-690天
//                else return "NORMAL"; // 正常还款
//            } else {
            // 非第一期：同样提高400天以上逾期的比例到10%
            if (overdueRandom < 0.10) return "M1_7";     // 10% -> 逾期1-7天
            else if (overdueRandom < 0.20) return "M7_15"; // 10% -> 逾期7-15天
            else if (overdueRandom < 0.30) return "M15_30"; // 10% -> 逾期15-30天
            else if (overdueRandom < 0.40) return "M30_60"; // 10% -> 逾期30-60天
            else if (overdueRandom < 0.50) return "M60_90"; // 10% -> 逾期60-90天
            else if (overdueRandom < 0.55) return "M90_120"; // 5% -> 逾期90-120天
            else if (overdueRandom < 0.60) return "M120_150"; // 5% -> 逾期120-150天
            else if (overdueRandom < 0.65) return "M150_180"; // 5% -> 逾期150-180天
            else if (overdueRandom < 0.70) return "M180_210"; // 5% -> 逾期180-210天
            else if (overdueRandom < 0.75) return "M210_240"; // 5% -> 逾期210-240天
            else if (overdueRandom < 0.80) return "M240_270"; // 5% -> 逾期240-270天
            else if (overdueRandom < 0.83) return "M270_300"; // 5% -> 逾期270-300天
            else if (overdueRandom < 0.84) return "M300_330"; // 2% -> 逾期300-330天
            else if (overdueRandom < 0.85) return "M330_360"; // 2% -> 逾期330-360天
            else if (overdueRandom < 0.86) return "M360_390"; // 1% -> 逾期360-390天
            else if (overdueRandom < 0.87) return "M390_420"; // 1% -> 逾期390-420天
            else if (overdueRandom < 0.88) return "M420_450"; // 1% -> 逾期420-450天
            else if (overdueRandom < 0.89) return "M450_480"; // 1% -> 逾期450-480天
            else if (overdueRandom < 0.90) return "M480_510"; // 1% -> 逾期480-510天
            else if (overdueRandom < 0.91) return "M510_540"; // 1% -> 逾期510-540天
            else if (overdueRandom < 0.92) return "M540_570"; // 1% -> 逾期540-570天
            else if (overdueRandom < 0.93) return "M570_600"; // 1% -> 逾期570-600天
            else if (overdueRandom < 0.94) return "M600_630"; // 1% -> 逾期600-630天
            else if (overdueRandom < 0.95) return "M630_660"; // 1% -> 逾期630-660天
            else if (overdueRandom < 0.958) return "M660_690"; // 0.5% -> 逾期660-690天
            else if (overdueRandom < 0.95) return "M690_720"; // 0.3% -> 逾期690_720天
            else if (overdueRandom < 0.96) return "M720_750"; // 0.3% -> 逾期750_780天
            else if (overdueRandom < 0.98) return "M750_780"; // 0.3% -> 逾期750_780天
            else if (overdueRandom < 99) return "M780_820"; // 0.3% -> 逾期780_820天
            else return "NORMAL"; // 0.2% -> 逾期720天以上
//            }
        } else {
            return "NORMAL"; // 正常还款（74%）
        }
    }

    private static double generateUniformRandomFromDueDateAndPeriod(LocalDate dueDate, int period) {
        // 策略1：从dueDate中提取年月信息
        String yearMonth = dueDate.toString().substring(0, 7); // 提取"2023-09"部分
        String year = yearMonth.substring(0, 4); // 提取年份"2023"
        String month = yearMonth.substring(5, 7); // 提取月份"09"

        // 策略2：将年月转换为数字
        int yearInt = Integer.parseInt(year);
        int monthInt = Integer.parseInt(month);

        // 策略3：将期数信息纳入计算，确保不同期数的分布不同
        int periodFactor = period * 1000; // 期数乘以1000作为因子

        // 策略4：使用多个不同的质数进行取模运算，结合年月和期数信息
        long num1 = (yearInt * 10000L + monthInt * 100L + periodFactor) % 10007; // 质数10007
        long num2 = (yearInt * 1000L + monthInt * 1000L + periodFactor) % 9973;  // 质数9973
        long num3 = (yearInt * 100L + monthInt * 10000L + periodFactor) % 9923;  // 质数9923

        // 策略5：使用年月信息创建偏移量
        long num4 = (yearInt * monthInt + periodFactor) % 9901; // 质数9901

        // 策略6：使用位运算和异或操作增加随机性
        long mixed = (num1 ^ num2 ^ num3 ^ num4) & 0x7FFFFFFF; // 确保为正数

        // 策略7：使用正弦函数进一步打乱分布
        double sinValue = Math.sin(mixed * 0.0001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]

        // 策略8：使用年月信息增加变化
        double yearInfluence = (yearInt % 100) / 100.0 * 0.1; // 10%的影响，基于年份
        double monthInfluence = (monthInt / 12.0) * 0.1; // 10%的影响，基于月份
        double periodInfluence = (period / 12.0) * 0.15; // 15%的影响，期数影响更大

        // 策略9：使用年月创建不同的偏移量，确保不同月份的分布错开
        double yearMonthOffset = ((yearInt * 12 + monthInt) * 0.01) % 1.0; // 年月偏移量

        // 策略10：使用期数创建不同的偏移量，确保不同期数的分布错开
        double periodOffset = (period * 0.1) % 1.0; // 期数偏移量

        // 最终结果：混合所有策略，加入年月和期数偏移
        double result = (normalized + yearInfluence + monthInfluence + periodInfluence + yearMonthOffset + periodOffset) % 1.0;

        return result;
    }

    /**
     * 从放款时间、dueDate和期数生成均匀分布的随机数
     * 使用放款时间frTime的前两位（如"2023-09"）、dueDate的前两位和期数均分，确保每个月都有逾期数据
     * 按照期数来均分逾期数据
     */
    private static double generateUniformRandomFromFrTimeDueDateAndPeriod(String frTime, LocalDate dueDate, int period) {
        // 策略1：从放款时间中提取年月信息
//        String frYearMonth = frTime.substring(0, 7); // 提取"2023-09"部分
//        String frYear = frYearMonth.substring(0, 4); // 提取年份"2023"
//        String frMonth = frYearMonth.substring(5, 7); // 提取月份"09"

        // 策略2：从dueDate中提取年月信息
        String dueYearMonth = dueDate.toString().substring(0, 7); // 提取"2023-09"部分
        String dueYear = dueYearMonth.substring(0, 4); // 提取年份"2023"
        String dueMonth = dueYearMonth.substring(5, 7); // 提取月份"09"

        // 策略3：将年月转换为数字
//        int frYearInt = Integer.parseInt(frYear);
//        int frMonthInt = Integer.parseInt(frMonth);
        int dueYearInt = Integer.parseInt(dueYear);
        int dueMonthInt = Integer.parseInt(dueMonth);

        // 策略4：将期数信息纳入计算，确保不同期数的分布不同
        int periodFactor = period * 1000; // 期数乘以1000作为因子

        // 策略5：使用多个不同的质数进行取模运算，结合放款时间、dueDate和期数信息
//        long num1 = (frYearInt * 10000L + frMonthInt * 100L + periodFactor) % 10007; // 质数10007
        long num2 = (dueYearInt * 1000L + dueMonthInt * 1000L + periodFactor) % 9973;  // 质数9973
//        long num3 = (frYearInt * 100L + dueYearInt * 10000L + periodFactor) % 9923;  // 质数9923

        // 策略6：使用年月信息创建偏移量
        long num4 = (dueYearInt * dueMonthInt + periodFactor) % 9901; // 质数9901

        // 策略7：使用位运算和异或操作增加随机性
        long mixed = (num2 ^ num4) & 0x7FFFFFFF; // 确保为正数

        // 策略8：使用正弦函数进一步打乱分布
        double sinValue = Math.sin(mixed * 0.0001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]

        // 策略9：使用年月信息增加变化
/*        double frYearInfluence = (frYearInt % 100) / 100.0 * 0.05; // 5%的影响，基于放款年份
        double frMonthInfluence = (frMonthInt / 12.0) * 0.05; // 5%的影响，基于放款月份*/
        double dueYearInfluence = (dueYearInt % 100) / 100.0 * 0.05; // 5%的影响，基于dueDate年份
        double dueMonthInfluence = (dueMonthInt / 12.0) * 0.05; // 5%的影响，基于dueDate月份
        double periodInfluence = (period / 12.0) * 0.15; // 15%的影响，期数影响更大

        // 策略10：使用年月创建不同的偏移量，确保不同月份的分布错开
//        double frYearMonthOffset = ((frYearInt * 12 + frMonthInt) * 0.01) % 1.0; // 放款年月偏移量
        double dueYearMonthOffset = ((dueYearInt * 12 + dueMonthInt) * 0.01) % 1.0; // dueDate年月偏移量

        // 策略11：使用期数创建不同的偏移量，确保不同期数的分布错开
        double periodOffset = (period * 0.1) % 1.0; // 期数偏移量

        // 最终结果：混合所有策略，加入年月和期数偏移
        double result = (normalized + dueYearInfluence + dueMonthInfluence +
                periodInfluence + dueYearMonthOffset + periodOffset) % 1.0;

        return result;
    }

    /**
     * 从dueDate和期数生成均匀分布的随机数
     * 使用dueDate的前两位（如"2023-09"）均分，确保每个月都有逾期数据
     * 专门用于第一期（period == 1）的逾期已还数据分配
     */
//    private static double generateUniformRandomFromDueDateAndPeriod(LocalDate dueDate, int period) {
//        // 策略1：从dueDate中提取年月信息
//        String yearMonth = dueDate.toString().substring(0, 7); // 提取"2023-09"部分
//        String year = yearMonth.substring(0, 4); // 提取年份"2023"
//        String month = yearMonth.substring(5, 7); // 提取月份"09"
//
//        // 策略2：将年月转换为数字
//        int yearInt = Integer.parseInt(year);
//        int monthInt = Integer.parseInt(month);
//
//        // 策略3：将期数信息纳入计算，确保不同期数的分布不同
//        int periodFactor = period * 1000; // 期数乘以1000作为因子
//
//        // 策略4：使用多个不同的质数进行取模运算，结合年月和期数信息
//        long num1 = (yearInt * 10000L + monthInt * 100L + periodFactor) % 10007; // 质数10007
//        long num2 = (yearInt * 1000L + monthInt * 1000L + periodFactor) % 9973;  // 质数9973
//        long num3 = (yearInt * 100L + monthInt * 10000L + periodFactor) % 9923;  // 质数9923
//
//        // 策略5：使用年月信息创建偏移量
//        long num4 = (yearInt * monthInt + periodFactor) % 9901; // 质数9901
//
//        // 策略6：使用位运算和异或操作增加随机性
//        long mixed = (num1 ^ num2 ^ num3 ^ num4) & 0x7FFFFFFF; // 确保为正数
//
//        // 策略7：使用正弦函数进一步打乱分布
//        double sinValue = Math.sin(mixed * 0.0001);
//        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]
//
//        // 策略8：使用年月信息增加变化
//        double yearInfluence = (yearInt % 100) / 100.0 * 0.1; // 10%的影响，基于年份
//        double monthInfluence = (monthInt / 12.0) * 0.1; // 10%的影响，基于月份
//        double periodInfluence = (period / 12.0) * 0.15; // 15%的影响，期数影响更大
//
//        // 策略9：使用年月创建不同的偏移量，确保不同月份的分布错开
//        double yearMonthOffset = ((yearInt * 12 + monthInt) * 0.01) % 1.0; // 年月偏移量
//
//        // 策略10：使用期数创建不同的偏移量，确保不同期数的分布错开
//        double periodOffset = (period * 0.1) % 1.0; // 期数偏移量
//
//        // 最终结果：混合所有策略，加入年月和期数偏移
//        double result = (normalized + yearInfluence + monthInfluence + periodInfluence + yearMonthOffset + periodOffset) % 1.0;
//
//        return result;
//    }

    /**
     * 从放款时间和期数生成均匀分布的随机数
     * 使用放款时间frTime的前两位（如"2023-09"）均分，确保每个月都有逾期数据
     */
    private static double generateUniformRandomFromFrTimeAndPeriod(String frTime, int period) {
        // 策略1：从放款时间中提取年月信息
        String yearMonth = frTime.substring(0, 7); // 提取"2023-09"部分
        String year = yearMonth.substring(0, 4); // 提取年份"2023"
        String month = yearMonth.substring(5, 7); // 提取月份"09"

        // 策略2：将年月转换为数字
        int yearInt = Integer.parseInt(year);
        int monthInt = Integer.parseInt(month);

        // 策略3：使用简单的时间戳计算，确保每个月都有比例
        // 将年月转换为从2023年1月开始的总月数
        int totalMonths = (yearInt - 2023) * 12 + (monthInt - 1);

        // 策略4：使用期数创建不同的偏移量，确保不同期数的分布错开
        int periodOffset = period * 1000; // 期数偏移量

        // 策略5：使用总月数和期数偏移量生成稳定的随机数
        long seed = totalMonths * 10000L + periodOffset;

        // 策略6：使用简单的哈希算法确保分布均匀
        long hash = seed * 31L + 17L; // 使用质数31和17
        hash = hash ^ (hash >>> 16); // 位运算增加随机性
        hash = hash ^ (hash >>> 8);
        hash = hash ^ (hash >>> 4);
        hash = hash ^ (hash >>> 2);
        hash = hash ^ (hash >>> 1);

        // 策略7：将哈希值映射到0-1范围
        double result = Math.abs(hash) % 10000 / 10000.0;

        return result;
    }

    /**
     * 从订单号和期数生成均匀分布的随机数
     * 使用多种策略确保即使订单号递增也能产生均匀分布
     */
    private static double generateUniformRandomFromOrderNoAndPeriod(String orderNo, int period) {
        // 策略1：使用订单号的多个部分
        String orderNoDigits = orderNo.replaceAll("[^0-9]", ""); // 提取数字部分
        long orderNoNumeric = orderNoDigits.isEmpty() ? 0 : Long.parseLong(orderNoDigits.substring(0, Math.min(8, orderNoDigits.length())));

        // 策略2：使用订单号的哈希值
        long orderHash = Math.abs(orderNo.hashCode());

        // 策略3：将期数信息纳入计算
        int periodFactor = period * 1000; // 期数乘以1000作为因子

        // 策略4：使用多个不同的质数进行取模运算
        long num1 = (orderNoNumeric + periodFactor) % 10007; // 质数10007
        long num2 = (orderHash + periodFactor) % 9973;  // 质数9973
        long num3 = (orderNoNumeric * 1000L + orderHash + periodFactor) % 9923;  // 质数9923

        // 策略5：使用订单号的不同位数
        long num4 = 0;
        if (orderNoDigits.length() >= 4) {
            // 使用订单号的后4位
            long lastFour = Long.parseLong(orderNoDigits.substring(Math.max(0, orderNoDigits.length() - 4)));
            num4 = (lastFour + periodFactor) % 9901; // 质数9901
        }

        // 策略6：使用位运算和异或操作增加随机性
        long mixed = (num1 ^ num2 ^ num3 ^ num4) & 0x7FFFFFFF; // 确保为正数

        // 策略7：使用正弦函数进一步打乱分布
        double sinValue = Math.sin(mixed * 0.0001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]

        // 策略8：使用期数信息增加变化
        double periodInfluence = (period / 12.0) * 0.2; // 20%的影响，期数影响更大

        // 策略9：使用订单号的不同部分创建偏移量
        double orderOffset1 = (orderNoNumeric % 1000) / 1000.0 * 0.1; // 10%的影响，基于订单号数字
        double orderOffset2 = (orderHash % 1000) / 1000.0 * 0.1; // 10%的影响，基于订单号哈希

        // 策略10：使用期数创建不同的偏移量，确保不同期数的分布错开
        double periodOffset = (period * 0.1) % 1.0; // 期数偏移量

        // 最终结果：混合所有策略，加入期数和订单号偏移
        double result = (normalized + periodInfluence + orderOffset1 + orderOffset2 + periodOffset) % 1.0;

        return result;
    }

    /**
     * 根据年月递增生成逾期随机数
     * 根据loanDate的年月（如2025-08）按月递增0-3%，最终总逾期数控制在6%左右
     */
    private static double generateOverdueRandomWithYearMonthIncrement(LocalDate loanDate, int term, String orderNo) {
        // 获取年月信息
        int year = loanDate.getYear();
        int month = loanDate.getMonthValue();
        
        // 计算从基准年月（2020-01）开始的月数
        int baseYear = 2020;
        int baseMonth = 1;
        int totalMonths = (year - baseYear) * 12 + (month - baseMonth);
        
        // 按月递增，每月递增0.1%，最大递增3%
        double monthIncrement = totalMonths * 0.001; // 每月递增0.1%
        monthIncrement = Math.min(monthIncrement, 0.03); // 限制最大递增3%
        monthIncrement = Math.max(monthIncrement, 0.0); // 确保不小于0
        
        // 基础逾期比例6%
        double baseOverdueRate = 0.06;
        
        // 计算最终的逾期阈值
        double overdueThreshold = baseOverdueRate + monthIncrement;
        
        // 使用订单号和期数生成随机数
        long orderHash = Math.abs(orderNo.hashCode());
        int termFactor = term * 1000;
        
        // 使用年月信息生成种子
        long seed = (year * 10000L + month * 100L + termFactor + orderHash) % 10007;
        
        // 生成0-1之间的随机数
        double randomValue = (seed % 10000) / 10000.0;
        
        // 根据逾期阈值调整随机数分布
        // 如果随机数小于阈值，则标记为逾期
        return randomValue;
    }

    /**
     * 从放款日期、期数和订单号生成均匀分布的随机数
     * 使用多种策略确保即使订单号递增，不同期限的提前还款也能产生均匀分布
     */
    private static double generateUniformRandomFromLoanDateTermAndOrderNo(LocalDate loanDate, int term, String orderNo) {
        // 策略1：使用日期的多个组成部分
        int year = loanDate.getYear();
        int month = loanDate.getMonthValue();
        int day = loanDate.getDayOfMonth();
        int dayOfYear = loanDate.getDayOfYear();

        // 策略2：使用订单号的哈希值，确保递增订单号也能产生均匀分布
        long orderHash = Math.abs(orderNo.hashCode());

        // 策略3：将期数信息纳入计算，确保不同期数的分布不同
        int termFactor = term * 1000; // 期数乘以1000作为因子

        // 策略4：使用多个不同的质数进行取模运算，结合所有信息
        long num1 = (year * 10000L + month * 100L + day + termFactor + orderHash) % 10007; // 质数10007
        long num2 = (dayOfYear * 1000L + month * 100L + day + termFactor + orderHash) % 9973;  // 质数9973
        long num3 = (year * 1000L + dayOfYear + termFactor + orderHash) % 9923;  // 质数9923

        // 策略5：使用订单号的数字部分增加变化
        String orderNoDigits = orderNo.replaceAll("[^0-9]", ""); // 提取数字部分
        long orderNoNumeric = orderNoDigits.isEmpty() ? 0 : Long.parseLong(orderNoDigits.substring(0, Math.min(8, orderNoDigits.length())));
        long num4 = (num1 + orderNoNumeric + termFactor) % 9901; // 质数9901

        // 策略6：使用位运算和异或操作增加随机性
        long mixed = (num1 ^ num2 ^ num3 ^ num4) & 0x7FFFFFFF; // 确保为正数

        // 策略7：使用正弦函数进一步打乱分布
        double sinValue = Math.sin(mixed * 0.0001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]

        // 策略8：使用月份、日期、期数和订单号信息增加变化
        double monthInfluence = (month / 12.0) * 0.1; // 10%的影响
        double dayInfluence = (day / 31.0) * 0.05; // 5%的影响
        double termInfluence = (term / 12.0) * 0.15; // 15%的影响，期数影响更大
        double orderInfluence = (orderNoNumeric % 1000) / 1000.0 * 0.1; // 10%的影响，基于订单号

        // 策略9：使用期数创建不同的偏移量，确保不同期数的分布错开
//        double termOffset = (term * 0.1) % 1.0; // 期数偏移量
        double termOffset = (term * 0.01) % 1.0; // 期数偏移量改为1%

        // 策略10：使用订单号的哈希值创建偏移量，确保递增订单号的分布均匀
        double orderOffset = (orderHash % 1000) / 1000.0 * 0.05; // 5%的影响，基于订单号哈希

        // 最终结果：混合所有策略，加入期数和订单号偏移
        double result = (normalized + monthInfluence + dayInfluence + termInfluence + orderInfluence + termOffset + orderOffset) % 1.0;

        return result;
    }

    /**
     * 判断该期还款计划是否应该逾期
     */
    private static boolean shouldPlanOverdue(CustomerRepayPlan plan, String overdueBucket, LocalDate now) {
        if (overdueBucket == null) return false;

        // 根据期数和逾期区间决定是否逾期
        // 例如：如果选择M2逾期，则前2期正常还款，第3期开始逾期
        int planTerm = plan.getBillTenor().intValue();

        switch (overdueBucket) {
            case "M1":
                return planTerm >= 1;
            case "M2":
                return planTerm >= 2;
            case "M3":
                return planTerm >= 3;
            case "M4":
                return planTerm >= 4;
            case "M5":
                return planTerm >= 5;
            case "M6":
                return planTerm >= 6;
            default:
                return false;
        }
    }

    /**
     * 应用逾期逻辑（支持新的逾期区间和提前结清）
     */
    private static void applyOverdueLogic(CustomerRepayPlan plan, CustomerOrder order,
                                          LocalDate dueDate, LocalDate now, String overdueBucket, List<CustomerRepayPlan> allPlans) {

//        // 检查是否应该提前结清（5%的概率，在还了一半期数后）
//        if (shouldEarlySettle(order, plan)) {
//            applyEarlySettlementLogic(plan, dueDate, allPlans, order);
//            return;
//        }

        // 根据新的逾期区间处理
        if ("NORMAL".equals(overdueBucket)) {
            // 正常还款，确保实际还款日期小于等于2025-09-30
            LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;

            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);
            plan.setActualRepayMoney(plan.getNowPayAmount());
            plan.setOverdueDays(0);
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setPenaltyInterest(BigDecimal.ZERO);
        } else {
            // 逾期后还款
            LocalDate actualRepayDate = calculateActualRepayDateByBucket(dueDate, overdueBucket);
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);

            long actualOverdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
            plan.setOverdueDays((int) actualOverdueDays);

            // 计算罚息
            if (actualOverdueDays > 0) {
                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = plan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(actualOverdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                plan.setPenaltyInterest(penaltyInterest);
            } else {
                plan.setPenaltyInterest(BigDecimal.ZERO);
            }

            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setActualRepayMoney(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
        }
    }

    /**
     * 应用逾期逻辑（5%逾期率，还款日期在2025-10-01之前）
     * 逾期已还的天数分布：1-7天、7-15天、15-30天、30-60天、60-90天
     */
    private static void applyOverdueLogicWith5Percent(CustomerRepayPlan plan, CustomerOrder order,
                                                      LocalDate dueDate, LocalDate now, String overdueBucket, List<CustomerRepayPlan> allPlans) {

        // 根据新的逾期区间处理
        if ("NORMAL".equals(overdueBucket)) {
            // 正常还款，确保实际还款日期小于等于2025-09-30
            LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;

            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);
            plan.setActualRepayMoney(plan.getNowPayAmount());
            plan.setOverdueDays(0);
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setPenaltyInterest(BigDecimal.ZERO);
        } else {
            // 逾期后还款，确保还款日期在2025-10-01之前
            LocalDate actualRepayDate = calculateActualRepayDateByBucket5Percent(dueDate, overdueBucket);
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);

            long actualOverdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
            plan.setOverdueDays((int) actualOverdueDays);

            // 计算罚息
            if (actualOverdueDays > 0) {
                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = plan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(actualOverdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                plan.setPenaltyInterest(penaltyInterest);
            } else {
                plan.setPenaltyInterest(BigDecimal.ZERO);
            }

            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setActualRepayMoney(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
        }
    }

    /**
     * 应用逾期逻辑（详细逾期天数分布，还款日期在2025-10-01之前）
     * 支持最高720天的逾期天数分布
     */
    private static void applyOverdueLogicWithDetailedDistribution(CustomerRepayPlan plan, CustomerOrder order,
                                                                  LocalDate dueDate, LocalDate now, String overdueBucket, List<CustomerRepayPlan> allPlans) {

        // 根据新的逾期区间处理
        if ("NORMAL".equals(overdueBucket)) {
            // 正常还款，确保实际还款日期小于等于2025-09-30
            LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
            LocalDate actualRepayDate = dueDate.isAfter(maxRepayDate) ? maxRepayDate : dueDate;

            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);
            plan.setActualRepayMoney(plan.getNowPayAmount());
            plan.setOverdueDays(0);
            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setPenaltyInterest(BigDecimal.ZERO);
        } else {
            // 逾期后还款，确保还款日期在2025-10-01之前
            LocalDate actualRepayDate = calculateActualRepayDateByBucketDetailed(dueDate, overdueBucket);
            plan.setRepayStatus("已结清");
            plan.setActualRepayDate(actualRepayDate);

            long actualOverdueDays = actualRepayDate.toEpochDay() - dueDate.toEpochDay();
            plan.setOverdueDays((int) actualOverdueDays);

            // 计算罚息
            if (actualOverdueDays > 3) {
                BigDecimal penaltyRate = plan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = plan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(actualOverdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                plan.setPenaltyInterest(penaltyInterest);
            } else {
                plan.setPenaltyInterest(BigDecimal.ZERO);
            }

            plan.setActualPrincipal(plan.getNowPayPrincipal());
            plan.setActualInterest(plan.getNowPayInterest());
            plan.setActualRepayMoney(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
            plan.setNowPayAmount(plan.getNowPayAmount().add(plan.getPenaltyInterest()));
        }
    }


    /**
     * 计算逾期天数
     */
    private static long calculateOverdueDays(LocalDate dueDate, LocalDate now, String overdueBucket) {
        switch (overdueBucket) {
            case "M1":
                return 15 + random.nextInt(16); // 15-30天
            case "M2":
                return 31 + random.nextInt(30); // 31-60天
            case "M3":
                return 61 + random.nextInt(30); // 61-90天
            case "M4":
                return 91 + random.nextInt(30); // 91-120天
            case "M5":
                return 121 + random.nextInt(30); // 121-150天
            case "M6":
                return 151 + random.nextInt(30); // 151-180天
            default:
                return 1 + random.nextInt(30); // 默认1-30天
        }
    }

    /**
     * 根据新的逾期区间计算实际还款日期
     * 确保实际还款日期只能小于等于2025-09-30
     */
    private static LocalDate calculateActualRepayDateByBucket(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30); // 最大还款日期
        LocalDate actualRepayDate;

        switch (overdueBucket) {
            case "M1_7":
                actualRepayDate = dueDate.plusDays(1 + random.nextInt(7)); // 1-7天后还款
                break;
            case "M8_15":
                actualRepayDate = dueDate.plusDays(8 + random.nextInt(8)); // 8-15天后还款
                break;
            case "M16_30":
                actualRepayDate = dueDate.plusDays(16 + random.nextInt(15)); // 16-30天后还款
                break;
            case "M30_60":
                actualRepayDate = dueDate.plusDays(30 + random.nextInt(31)); // 30-60天后还款
                break;
            case "M60_90":
                actualRepayDate = dueDate.plusDays(60 + random.nextInt(31)); // 60-90天后还款
                break;
            case "M90_180":
                actualRepayDate = dueDate.plusDays(90 + random.nextInt(91)); // 90-180天后还款
                break;
            default:
                return dueDate; // 正常还款
        }

        // 确保实际还款日期不超过2025-09-30
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }

        return actualRepayDate;
    }

    /**
     * 根据5%逾期率的逾期区间计算实际还款日期
     * 确保实际还款日期在2025-10-01之前
     * 逾期已还的天数分布：1-7天、7-15天、15-30天、30-60天、60-90天
     */
    private static LocalDate calculateActualRepayDateByBucket5Percent(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30); // 最大还款日期（2025-10-01之前）
        LocalDate actualRepayDate;

        switch (overdueBucket) {
            case "M1_7":
                actualRepayDate = dueDate.plusDays(1 + random.nextInt(7)); // 1-7天后还款
                break;
            case "M7_15":
                actualRepayDate = dueDate.plusDays(7 + random.nextInt(9)); // 7-15天后还款
                break;
            case "M15_30":
                actualRepayDate = dueDate.plusDays(15 + random.nextInt(16)); // 15-30天后还款
                break;
            case "M30_60":
                actualRepayDate = dueDate.plusDays(30 + random.nextInt(31)); // 30-60天后还款
                break;
            case "M60_90":
                actualRepayDate = dueDate.plusDays(60 + random.nextInt(31)); // 60-90天后还款
                break;
            default:
                return dueDate; // 正常还款
        }

        // 确保实际还款日期在2025-10-01之前
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }

        return actualRepayDate;
    }

    /**
     * 根据详细逾期天数分布计算实际还款日期
     * 确保实际还款日期在2025-10-01之前
     * 支持最高720天的逾期天数分布
     */
    private static LocalDate calculateActualRepayDateByBucketDetailed(LocalDate dueDate, String overdueBucket) {
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30); // 最大还款日期（2025-10-01之前）
        LocalDate actualRepayDate;

        switch (overdueBucket) {
            case "M1_7":
                actualRepayDate = dueDate.plusDays(1 + random.nextInt(7)); // 1-7天后还款
                break;
            case "M7_15":
                actualRepayDate = dueDate.plusDays(7 + random.nextInt(9)); // 7-15天后还款
                break;
            case "M15_30":
                actualRepayDate = dueDate.plusDays(15 + random.nextInt(16)); // 15-30天后还款
                break;
            case "M30_60":
                actualRepayDate = dueDate.plusDays(30 + random.nextInt(31)); // 30-60天后还款
                break;
            case "M60_90":
                actualRepayDate = dueDate.plusDays(60 + random.nextInt(31)); // 60-90天后还款
                break;
            case "M90_120":
                actualRepayDate = dueDate.plusDays(90 + random.nextInt(31)); // 90-120天后还款
                break;
            case "M120_150":
                actualRepayDate = dueDate.plusDays(120 + random.nextInt(31)); // 120-150天后还款
                break;
            case "M150_180":
                actualRepayDate = dueDate.plusDays(150 + random.nextInt(31)); // 150-180天后还款
                break;
            case "M180_210":
                actualRepayDate = dueDate.plusDays(180 + random.nextInt(31)); // 180-210天后还款
                break;
            case "M210_240":
                actualRepayDate = dueDate.plusDays(210 + random.nextInt(31)); // 210-240天后还款
                break;
            case "M240_270":
                actualRepayDate = dueDate.plusDays(240 + random.nextInt(31)); // 240-270天后还款
                break;
            case "M270_300":
                actualRepayDate = dueDate.plusDays(270 + random.nextInt(31)); // 270-300天后还款
                break;
            case "M300_330":
                actualRepayDate = dueDate.plusDays(300 + random.nextInt(31)); // 300-330天后还款
                break;
            case "M330_360":
                actualRepayDate = dueDate.plusDays(330 + random.nextInt(31)); // 330-360天后还款
                break;
            case "M360_390":
                actualRepayDate = dueDate.plusDays(360 + random.nextInt(31)); // 360-390天后还款
                break;
            case "M390_420":
                actualRepayDate = dueDate.plusDays(390 + random.nextInt(31)); // 390-420天后还款
                break;
            case "M420_450":
                actualRepayDate = dueDate.plusDays(420 + random.nextInt(31)); // 420-450天后还款
                break;
            case "M450_480":
                actualRepayDate = dueDate.plusDays(450 + random.nextInt(31)); // 450-480天后还款
                break;
            case "M480_510":
                actualRepayDate = dueDate.plusDays(480 + random.nextInt(31)); // 480-510天后还款
                break;
            case "M510_540":
                actualRepayDate = dueDate.plusDays(510 + random.nextInt(31)); // 510-540天后还款
                break;
            case "M540_570":
                actualRepayDate = dueDate.plusDays(540 + random.nextInt(31)); // 540-570天后还款
                break;
            case "M570_600":
                actualRepayDate = dueDate.plusDays(570 + random.nextInt(31)); // 570-600天后还款
                break;
            case "M600_630":
                actualRepayDate = dueDate.plusDays(600 + random.nextInt(31)); // 600-630天后还款
                break;
            case "M630_660":
                actualRepayDate = dueDate.plusDays(630 + random.nextInt(31)); // 630-660天后还款
                break;
            case "M660_690":
                actualRepayDate = dueDate.plusDays(660 + random.nextInt(31)); // 660-690天后还款
                break;
            case "M690_720":
                actualRepayDate = dueDate.plusDays(690 + random.nextInt(31)); // 690-720天后还款
                break;
            case "M720_750":
                actualRepayDate = dueDate.plusDays(720 + random.nextInt(31)); // 逾期720_750天
                break;
            case "M750_780":
                actualRepayDate = dueDate.plusDays(750 + random.nextInt(31)); // 逾期750_780天
                break;
            case "M780_820":
                actualRepayDate = dueDate.plusDays(780 + random.nextInt(40)); // 逾期780_820天
                break;
            default:
                return dueDate; // 正常还款
        }

        // 确保实际还款日期在2025-10-01之前
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }

        return actualRepayDate;
    }

    /**
     * 计算实际还款日期（保留原方法以兼容性）
     */
    private static LocalDate calculateActualRepayDate(LocalDate dueDate, String overdueBucket) {
        switch (overdueBucket) {
            case "M1":
                return dueDate.plusDays(3 + random.nextInt(16)); // 3-30天后还款
            case "M2":
                return dueDate.plusDays(31 + random.nextInt(30)); // 31-60天后还款
            case "M3":
                return dueDate.plusDays(61 + random.nextInt(30)); // 61-90天后还款
            case "M4":
                return dueDate.plusDays(91 + random.nextInt(30)); // 91-120天后还款
            case "M5":
                return dueDate.plusDays(121 + random.nextInt(30)); // 121-150天后还款
            case "M6":
                return dueDate.plusDays(151 + random.nextInt(30)); // 151-180天后还款
            default:
                return dueDate.plusDays(1 + random.nextInt(30)); // 默认1-30天后还款
        }
    }

    /**
     * 判断是否应该提前结清（5%概率，在bill_tenor到loan_term一半左右时）
     */
    private static boolean shouldEarlySettle(CustomerOrder order, CustomerRepayPlan plan) {
        int totalTerms = Integer.parseInt(order.getLoanTerm().replace("月", ""));
        int currentTerm = plan.getBillTenor().intValue();

        // 在bill_tenor到loan_term一半左右时可能提前结清
        // 允许在接近一半期数时就开始提前结清
        if (currentTerm < (totalTerms / 2)) {
            return false;
        }

        // 5%的概率提前结清
        return random.nextDouble() < 0.05;
    }

    /**
     * 应用提前结清逻辑
     */
    private static void applyEarlySettlementLogic(CustomerRepayPlan plan, LocalDate dueDate, List<CustomerRepayPlan> allPlans, CustomerOrder order) {
        // 提前结清：当bill_tenor到loan_term一半左右时，把剩余期数全部结清
        // 实际还款日期在due_date之前，但不超过2025-09-30
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
        LocalDate actualRepayDate = dueDate.minusDays(1 + random.nextInt(10)); // 提前1-10天还款

        // 确保实际还款日期不超过2025-09-30
        if (actualRepayDate.isAfter(maxRepayDate)) {
            actualRepayDate = maxRepayDate;
        }

        // 计算剩余未还所有期数的应还本金之和
        BigDecimal totalRemainingPrincipal = BigDecimal.ZERO;
        int currentTerm = plan.getBillTenor().intValue();
        int totalTerms = Integer.parseInt(order.getLoanTerm().replace("月", ""));

        // 计算从当前期到最后一期的所有应还本金（剩余未还的期数）
        for (int i = currentTerm; i <= totalTerms; i++) {
            final int termIndex = i; // 创建final变量用于lambda表达式
            // 找到对应期数的还款计划
            CustomerRepayPlan remainingPlan = allPlans.stream()
                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                    .findFirst()
                    .orElse(null);

            if (remainingPlan != null) {
                totalRemainingPrincipal = totalRemainingPrincipal.add(remainingPlan.getNowPayPrincipal());
            }
        }

        // 提前结清的这期的实际还款本金 = 剩余未还所有期数的应还本金之和
        plan.setActualPrincipal(totalRemainingPrincipal);

        // 提前结清的这期的实际还款利息 = 本期的应还利息（没有罚息）
        plan.setActualInterest(plan.getNowPayInterest());

        // 提前结清的这期的实际还款金额 = 实际还款本金 + 实际还款利息
        BigDecimal actualRepayMoney = totalRemainingPrincipal.add(plan.getNowPayInterest());
        plan.setActualRepayMoney(actualRepayMoney);

        // 设置提前结清这期的状态和日期
        plan.setRepayStatus("已结清");
        plan.setActualRepayDate(actualRepayDate);
        plan.setOverdueDays(0);
        plan.setPenaltyInterest(BigDecimal.ZERO); // 没有罚息

        // 将剩余期数的还款计划也标记为已结清，结清后的期数实还金额都是0
        for (int i = currentTerm + 1; i <= totalTerms; i++) {
            final int termIndex = i; // 创建final变量用于lambda表达式
            CustomerRepayPlan remainingPlan = allPlans.stream()
                    .filter(p -> p.getBillTenor().intValue() == termIndex)
                    .findFirst()
                    .orElse(null);

            if (remainingPlan != null) {
                remainingPlan.setRepayStatus("已结清");
                remainingPlan.setActualRepayDate(actualRepayDate);
                remainingPlan.setActualRepayMoney(BigDecimal.ZERO); // 结清后的期数实还金额都是0
                remainingPlan.setActualPrincipal(BigDecimal.ZERO); // 本金已在当前期还清
                remainingPlan.setActualInterest(BigDecimal.ZERO); // 利息已在当前期还清
                remainingPlan.setOverdueDays(0);
                remainingPlan.setPenaltyInterest(BigDecimal.ZERO); // 没有罚息
            }
        }
    }

    /**
     * 判断是否应该继续逾期（迁徙率逻辑）
     */
    private static boolean shouldContinueOverdue(String overdueBucket) {
        // 根据迁徙率决定是否继续逾期（迁徙率都小于100%）
        switch (overdueBucket) {
            case "M1":
                return random.nextDouble() < MIGRATION_RATES.get("M1_M2"); // 10%
            case "M2":
                return random.nextDouble() < MIGRATION_RATES.get("M2_M3"); // 40%
            case "M3":
                return random.nextDouble() < MIGRATION_RATES.get("M3_M4"); // 50%
            case "M4":
                return random.nextDouble() < MIGRATION_RATES.get("M4_M5"); // 60%
            case "M5":
                return random.nextDouble() < MIGRATION_RATES.get("M5_M6"); // 70%
            default:
                return random.nextDouble() < 0.05; // M6+有75%概率继续逾期
        }
    }


    private static String shouldOverdue() {
        double randomValue = random.nextDouble();

        if (randomValue < OVERDAY.get("D1_4")) {
            return "D1_4";
        }else if (randomValue < OVERDAY.get("D4_7")) {
            return "D4_7";
        } else if (randomValue < OVERDAY.get("D7_15")) {
            return "D7_15";
        } else if (randomValue < OVERDAY.get("D15_30")) {
            return "D15_30";
        } else if (randomValue < OVERDAY.get("D30_60")) {
            return "D30_60";
        } else if (randomValue < OVERDAY.get("D60_90")) {
            return "D60_90";
        } else if (randomValue < OVERDAY.get("D90_120")) {
            return "D90_120";
        } else {
            return "NORMAL";
        }
    }

    /**
     * 更新订单状态和剩余金额
     */
    private static void updateOrderStatusAndRemainAmount(CustomerOrder order, List<CustomerRepayPlan> plans, LocalDate now) {
        // 检查所有期数的还款状态
        boolean allSettled = plans.stream().allMatch(plan -> "已结清".equals(plan.getRepayStatus()));

        // 设置订单状态
        order.setStatus(allSettled ? "已结清" : "未结清");

        if (allSettled) {
            // 如果所有期数都已结清，设置结清日期为最后一笔实际还款日期
            LocalDate lastActualRepayDate = plans.stream()
                    .filter(plan -> plan.getActualRepayDate() != null)
                    .map(CustomerRepayPlan::getActualRepayDate)
                    .max(LocalDate::compareTo)
                    .orElse(null);

            if (lastActualRepayDate != null) {
                order.setSettleDate(lastActualRepayDate);
            }
            order.setRemainPayAmount(BigDecimal.ZERO);
        } else {
            // 计算剩余金额 = 贷款金额 - 已还本金
            BigDecimal totalPaidPrincipal = plans.stream()
                    .filter(plan -> "已结清".equals(plan.getRepayStatus()))
                    .map(CustomerRepayPlan::getActualPrincipal)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal remainAmount = order.getLoanAmount().subtract(totalPaidPrincipal);
            order.setRemainPayAmount(remainAmount.max(BigDecimal.ZERO)); // 确保不为负数

            order.setSettleDate(null);
        }

        // 设置放款时间等于客户创建时间
        order.setFrTime(order.getFrTime());
    }

    /**
     * 根据放款日期获取产品名称（按权重分布）
     */
    public static String getProductNameByDate(LocalDate loanDate) {
        // 2023年7月-12月：只有浩瀚小贷
        if (loanDate.isBefore(START_DATE.plusMonths(HAOHAN_ONLY_MONTHS))) {
            return "浩瀚小贷";
        }

        // 2024年1月后：多产品分布
        double randomValue = random.nextDouble();
        if (randomValue < PRODUCT_DISTRIBUTION.get("浩瀚小贷")) {
            return "浩瀚小贷";
        } else if (randomValue < PRODUCT_DISTRIBUTION.get("浩瀚小贷") + PRODUCT_DISTRIBUTION.get("盈峰小贷")) {
            return "盈峰小贷";
        } else if (randomValue < PRODUCT_DISTRIBUTION.get("浩瀚小贷") + PRODUCT_DISTRIBUTION.get("盈峰小贷") + PRODUCT_DISTRIBUTION.get("新网银行")) {
            return "新网银行";
        } else {
            return "江山小贷";
        }
    }

    /**
     * 生成完整的数据集并批量插入数据库（满足所有要求）
     */
    public DataGenerationResult generateCompleteDataSetWithBatchInsert() {
        // 清空现有数据
        DataGenerationResult result = new DataGenerationResult();

        // 批量插入缓存列表（线程安全）
        List<CustomerInfo> customerBatch = Collections.synchronizedList(new ArrayList<>());
        List<CustomerOrder> orderBatch = Collections.synchronizedList(new ArrayList<>());
        List<CustomerRepayPlan> repayPlanBatch = Collections.synchronizedList(new ArrayList<>());

        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

        // 原子变量用于线程安全的统计
        AtomicReference<BigDecimal> totalGeneratedAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> totalOutstandingAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> haohanOutstandingAmount = new AtomicReference<>(BigDecimal.ZERO);
        AtomicInteger totalProcessedOrders = new AtomicInteger(0);
        AtomicInteger batchCount = new AtomicInteger(0);

        // 从2023年7月到当前月份，每月生成数据
//        LocalDate currentDate = LocalDate.now();
        LocalDate currentDate = LocalDate.now().minusMonths(1); // 修改为上个月
        LocalDate month = START_DATE;

        log.info("开始生成数据（目标：50亿放款总额）...");
        log.info("使用多线程池，线程数: {}", THREAD_POOL_SIZE);

        try {
            int monthCounter = 0; // 使用计数器确保月度严格递增，避免日期计算误差
            
            while (month.isBefore(currentDate)) {
                // 计算该月应该生成的订单数量（递增，大规模数据）
                // 使用monthCounter确保每个月都准确递增，避免跨年计算错误
                int monthsFromStart = monthCounter;

                // 目标：50亿放款，20亿在贷余额
                // 总订单数：100万笔（50亿/5000元）
                // 26个月平均：约3.85万笔/月
                // 采用递增策略：首月25000笔，每月递增600笔，最后一月约40600笔
                int baseOrders = 25000; // 基础订单数（26个月，目标50亿放款，100万条订单）
                int monthlyOrders = baseOrders + (monthsFromStart * 600)+random.nextInt(100); // 每月递增600个订单，保持爬坡趋势
//                int baseOrders = 10000; // 基础订单数（26个月，目标50亿放款，100万条订单）
//                int monthlyOrders = baseOrders + (monthsFromStart * 60)+random.nextInt(10); // 每月递增600个订单，保持爬坡趋势

//                int baseOrders = 300; // 基础订单数（26个月，目标5000万，10000条订单）
//                int monthlyOrders = baseOrders + (monthsFromStart * 8); // 每月递增8个订单

                // 针对2025年4月到2025年9月的6个月，适度增加放款量以达到20亿在贷余额
//                 这6个月的订单是形成在贷余额的主要来源
                if (month.getYear() == 2025 && month.getMonthValue() >= 4 && month.getMonthValue() <= 9) {
                    // 提升25%，确保在贷余额达到20亿
                    // 这6个月需要产生约32万笔订单（20亿/5000元），月均5.33万笔
                    monthlyOrders = (int) (monthlyOrders * 1.9); // 提升90%
                    log.info("【在贷余额增强】{} 月份订单数量提升至: {}", month, monthlyOrders);
                }
//                int monthlyOrders=0;
//                if(month.getMonthValue() == 8){
//                    monthlyOrders=76063;
//                }else if(month.getMonthValue() ==9){
//                    monthlyOrders=77017;
//                }


                
                monthCounter++; // 月份计数器递增

                log.info("生成 {} 月份数据，订单数量: {}", month, monthlyOrders);

                // 使用多线程生成该月数据
                List<Future<OrderDataPackage>> futures = new ArrayList<>();

                // 将订单分成多个批次，每个线程处理一部分
                int ordersPerThread = Math.max(1, monthlyOrders / THREAD_POOL_SIZE);
                int remainingOrders = monthlyOrders;

                while (remainingOrders > 0) {
                    int ordersForThisThread = Math.min(ordersPerThread, remainingOrders);
//                    int ordersForThisThread = 1;

                    final int finalOrdersForThisThread = ordersForThisThread;
                    final LocalDate finalMonth = month;

                    int finalMonthlyOrders = monthlyOrders;
                    Future<OrderDataPackage> future = executorService.submit(() ->
                            generateOrderDataBatch(finalMonth, finalOrdersForThisThread, finalMonthlyOrders));
                    futures.add(future);

                    remainingOrders -= ordersForThisThread;
                }

                // 等待所有线程完成并收集结果
                for (Future<OrderDataPackage> future : futures) {
                    try {
                        OrderDataPackage orderPackage = future.get();

                        // 添加到批量插入缓存
                        customerBatch.addAll(orderPackage.getCustomers());
                        orderBatch.addAll(orderPackage.getOrders());
                        repayPlanBatch.addAll(orderPackage.getRepayPlans());

                        // 更新统计（原子操作）
                        totalGeneratedAmount.updateAndGet(amount -> amount.add(orderPackage.getTotalLoanAmount()));
                        totalOutstandingAmount.updateAndGet(amount -> amount.add(orderPackage.getTotalOutstandingAmount()));
                        haohanOutstandingAmount.updateAndGet(amount -> amount.add(orderPackage.getHaohanOutstandingAmount()));
                        totalProcessedOrders.addAndGet(orderPackage.getOrderCount());

                        // 检查是否需要批量插入
                        if (customerBatch.size() >= BATCH_SIZE) {
                            processBatchInsert(customerBatch, orderBatch, repayPlanBatch,
                                    batchCount, totalProcessedOrders, totalGeneratedAmount, totalOutstandingAmount);
                        }

                    } catch (Exception e) {
                        log.error("处理订单数据时发生异常", e);
                    }
                }

                month = month.plusMonths(1);
            }

            // 插入剩余的数据（如果缓存中还有数据）
            if (!customerBatch.isEmpty()) {
                processBatchInsert(customerBatch, orderBatch, repayPlanBatch,
                        batchCount, totalProcessedOrders, totalGeneratedAmount, totalOutstandingAmount);
            }

            // 输出最终统计信息
            log.info("\n=== 数据生成完成 ===");
            log.info("总处理订单数: {}", totalProcessedOrders.get());
            log.info("总批次: {}", batchCount.get());
            log.info("总投放金额: {} 亿", totalGeneratedAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
            log.info("在途余额: {} 亿", totalOutstandingAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
            log.info("浩瀚小贷在途余额: {} 亿", haohanOutstandingAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));

        } finally {
            // 关闭线程池
            executorService.shutdown();
        }

        return result;
    }

    /**
     * 批量插入数据到数据库（单条插入）
     */
    private void batchInsertData(CustomerInfo customer, CustomerOrder order, List<CustomerRepayPlan> repayPlans) {
        try {
            // 插入客户信息
            customerInfoMapper.insert(customer);

            // 插入订单信息
            customerOrderMapper.insert(order);

            // 批量插入还款计划
            for (CustomerRepayPlan plan : repayPlans) {
                customerRepayPlanMapper.insert(plan);
            }

        } catch (Exception e) {
            System.err.println("插入数据失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 批量插入数据到数据库（真正的批量插入）
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchInsertDataBatch(List<CustomerInfo> customers, List<CustomerOrder> orders, List<CustomerRepayPlan> repayPlans) {
        try {
            log.info("开始批量插入数据，客户数: {}, 订单数: {}, 还款计划数: {}",
                    customers.size(), orders.size(), repayPlans.size());

            // 分批插入以避免连接超时
            insertCustomersInBatches(customers);
            insertOrdersInBatches(orders);
            insertRepayPlansInBatches(repayPlans);

            log.info("批量插入数据完成");
        } catch (Exception e) {
            log.error("批量插入失败", e);
            throw e; // 重新抛出异常确保事务回滚
        }
    }

    /**
     * 生成完整的数据集（内存版本，不插入数据库）
     */
    public static DataGenerationResult generateCompleteDataSet() {
        DataGenerationResult result = new DataGenerationResult();
        List<CustomerInfo> allCustomers = new ArrayList<>();
        List<CustomerOrder> allOrders = new ArrayList<>();
        List<CustomerRepayPlan> allRepayPlans = new ArrayList<>();

        // 从2023年7月到当前月份，每月生成数据
        LocalDate currentDate = LocalDate.now();
        LocalDate month = START_DATE;

        BigDecimal totalGeneratedAmount = BigDecimal.ZERO;
        BigDecimal totalOutstandingAmount = BigDecimal.ZERO;
        BigDecimal haohanOutstandingAmount = BigDecimal.ZERO;

        while (!month.isAfter(currentDate)) {
            // 计算该月应该生成的订单数量（递增）
            int monthsFromStart = (int) (month.toEpochDay() - START_DATE.toEpochDay()) / 30;
            int baseOrders = 50; // 基础订单数
            int monthlyOrders = baseOrders + (monthsFromStart * 5); // 每月递增5个订单

            // 生成该月数据
            List<CustomerOrder> monthlyOrdersList = generateMonthlyData(month, monthlyOrders);

            // 为每个订单生成完整的客户信息和还款计划
            for (CustomerOrder order : monthlyOrdersList) {
                CustomerInfo customer = generateCustomerInfo(month);

                // 设置客户创建时间
                order.setFrTime(customer.getCreatedTime().substring(0, 10));

                // 生成还款计划
                List<CustomerRepayPlan> repayPlans = generateRepayPlan(order, 1, 0);

                // 设置订单客户ID
                order.setCustomerId(customer.getId());

                // 更新统计
                totalGeneratedAmount = totalGeneratedAmount.add(order.getLoanAmount());
                if ("未结清".equals(order.getStatus())) {
                    totalOutstandingAmount = totalOutstandingAmount.add(order.getRemainPayAmount());
                    if ("浩瀚小贷".equals(order.getProductName())) {
                        haohanOutstandingAmount = haohanOutstandingAmount.add(order.getRemainPayAmount());
                    }
                }

                allCustomers.add(customer);
                allOrders.add(order);
                allRepayPlans.addAll(repayPlans);
            }

            month = month.plusMonths(1);
        }

        result.setCustomers(allCustomers);
        result.setOrders(allOrders);
        result.setRepayPlans(allRepayPlans);

        // 输出统计信息
        log.info("数据生成完成:");
        log.info("总投放金额: " + totalGeneratedAmount);
        log.info("在途余额: " + totalOutstandingAmount);
        log.info("浩瀚小贷在途余额: " + haohanOutstandingAmount);

        return result;
    }

    /**
     * 计算Vintage逾期率
     */
    public static Map<String, VintageAnalysis> calculateVintageAnalysis(List<CustomerOrder> orders, List<CustomerRepayPlan> repayPlans) {
        Map<String, VintageAnalysis> vintageResults = new HashMap<>();
//        LocalDate now = LocalDate.now();
        LocalDate now = LocalDate.of(2025, 9, 30);

        // 按Vintage（放款月份）分组
        Map<String, List<CustomerOrder>> vintageGroups = orders.stream()
                .collect(Collectors.groupingBy(order -> order.getFrTime().substring(0, 7)));

        for (Map.Entry<String, List<CustomerOrder>> entry : vintageGroups.entrySet()) {
            String vintage = entry.getKey();
            List<CustomerOrder> vintageOrders = entry.getValue();

            VintageAnalysis analysis = new VintageAnalysis();
            analysis.setVintage(vintage);

            // 计算初始发放总额
            BigDecimal initialAmount = vintageOrders.stream()
                    .map(CustomerOrder::getLoanAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            analysis.setInitialAmount(initialAmount);

            // 计算各逾期阶段的余额
            BigDecimal overdue0Plus = calculateOverdueAmount(vintageOrders, repayPlans, 0, now);
            BigDecimal overdue30Plus = calculateOverdueAmount(vintageOrders, repayPlans, 30, now);
            BigDecimal overdue60Plus = calculateOverdueAmount(vintageOrders, repayPlans, 60, now);
            BigDecimal overdue90Plus = calculateOverdueAmount(vintageOrders, repayPlans, 90, now);

            analysis.setOverdue0Plus(overdue0Plus);
            analysis.setOverdue30Plus(overdue30Plus);
            analysis.setOverdue60Plus(overdue60Plus);
            analysis.setOverdue90Plus(overdue90Plus);

            // 计算逾期率
            if (initialAmount.compareTo(BigDecimal.ZERO) > 0) {
                analysis.setOverdue0PlusRate(overdue0Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                analysis.setOverdue30PlusRate(overdue30Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                analysis.setOverdue60PlusRate(overdue60Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
                analysis.setOverdue90PlusRate(overdue90Plus.divide(initialAmount, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
            }

            vintageResults.put(vintage, analysis);
        }

        return vintageResults;
    }

    /**
     * 计算指定逾期天数的未偿还本金余额
     */
    private static BigDecimal calculateOverdueAmount(List<CustomerOrder> vintageOrders, List<CustomerRepayPlan> repayPlans,
                                                     int overdueDays, LocalDate now) {
        Set<String> vintageOrderNos = vintageOrders.stream()
                .map(CustomerOrder::getOrderNo)
                .collect(Collectors.toSet());

        return repayPlans.stream()
                .filter(plan -> vintageOrderNos.contains(plan.getOrderNo()))
                .filter(plan -> {
                    if (plan.getActualRepayDate() == null) {
                        // 未还款的计划，检查是否逾期超过指定天数
                        long daysOverdue = now.toEpochDay() - plan.getDueDate().toEpochDay();
                        return daysOverdue > overdueDays;
                    }
                    return false;
                })
                .map(plan -> plan.getNowPayPrincipal())
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * Vintage分析结果类
     */
    public static class VintageAnalysis {
        private String vintage;
        private BigDecimal initialAmount;
        private BigDecimal overdue0Plus;
        private BigDecimal overdue30Plus;
        private BigDecimal overdue60Plus;
        private BigDecimal overdue90Plus;
        private BigDecimal overdue0PlusRate;
        private BigDecimal overdue30PlusRate;
        private BigDecimal overdue60PlusRate;
        private BigDecimal overdue90PlusRate;

        // Getters and Setters
        public String getVintage() {
            return vintage;
        }

        public void setVintage(String vintage) {
            this.vintage = vintage;
        }

        public BigDecimal getInitialAmount() {
            return initialAmount;
        }

        public void setInitialAmount(BigDecimal initialAmount) {
            this.initialAmount = initialAmount;
        }

        public BigDecimal getOverdue0Plus() {
            return overdue0Plus;
        }

        public void setOverdue0Plus(BigDecimal overdue0Plus) {
            this.overdue0Plus = overdue0Plus;
        }

        public BigDecimal getOverdue30Plus() {
            return overdue30Plus;
        }

        public void setOverdue30Plus(BigDecimal overdue30Plus) {
            this.overdue30Plus = overdue30Plus;
        }

        public BigDecimal getOverdue60Plus() {
            return overdue60Plus;
        }

        public void setOverdue60Plus(BigDecimal overdue60Plus) {
            this.overdue60Plus = overdue60Plus;
        }

        public BigDecimal getOverdue90Plus() {
            return overdue90Plus;
        }

        public void setOverdue90Plus(BigDecimal overdue90Plus) {
            this.overdue90Plus = overdue90Plus;
        }

        public BigDecimal getOverdue0PlusRate() {
            return overdue0PlusRate;
        }

        public void setOverdue0PlusRate(BigDecimal overdue0PlusRate) {
            this.overdue0PlusRate = overdue0PlusRate;
        }

        public BigDecimal getOverdue30PlusRate() {
            return overdue30PlusRate;
        }

        public void setOverdue30PlusRate(BigDecimal overdue30PlusRate) {
            this.overdue30PlusRate = overdue30PlusRate;
        }

        public BigDecimal getOverdue60PlusRate() {
            return overdue60PlusRate;
        }

        public void setOverdue60PlusRate(BigDecimal overdue60PlusRate) {
            this.overdue60PlusRate = overdue60PlusRate;
        }

        public BigDecimal getOverdue90PlusRate() {
            return overdue90PlusRate;
        }

        public void setOverdue90PlusRate(BigDecimal overdue90PlusRate) {
            this.overdue90PlusRate = overdue90PlusRate;
        }

        @Override
        public String toString() {
            return String.format("Vintage %s: 初始金额=%.2f, 0+逾期率=%.2f%%, 30+逾期率=%.2f%%, 60+逾期率=%.2f%%, 90+逾期率=%.2f%%",
                    vintage, initialAmount, overdue0PlusRate, overdue30PlusRate, overdue60PlusRate, overdue90PlusRate);
        }
    }

    /**
     * 订单数据包（用于多线程传递数据）
     */
    public static class OrderDataPackage {
        private List<CustomerInfo> customers;
        private List<CustomerOrder> orders;
        private List<CustomerRepayPlan> repayPlans;
        private BigDecimal totalLoanAmount;
        private BigDecimal totalOutstandingAmount;
        private BigDecimal haohanOutstandingAmount;
        private int orderCount;

        public OrderDataPackage() {
            this.customers = new ArrayList<>();
            this.orders = new ArrayList<>();
            this.repayPlans = new ArrayList<>();
            this.totalLoanAmount = BigDecimal.ZERO;
            this.totalOutstandingAmount = BigDecimal.ZERO;
            this.haohanOutstandingAmount = BigDecimal.ZERO;
            this.orderCount = 0;
        }

        // Getters and Setters
        public List<CustomerInfo> getCustomers() {
            return customers;
        }

        public void setCustomers(List<CustomerInfo> customers) {
            this.customers = customers;
        }

        public List<CustomerOrder> getOrders() {
            return orders;
        }

        public void setOrders(List<CustomerOrder> orders) {
            this.orders = orders;
        }

        public List<CustomerRepayPlan> getRepayPlans() {
            return repayPlans;
        }

        public void setRepayPlans(List<CustomerRepayPlan> repayPlans) {
            this.repayPlans = repayPlans;
        }

        public BigDecimal getTotalLoanAmount() {
            return totalLoanAmount;
        }

        public void setTotalLoanAmount(BigDecimal totalLoanAmount) {
            this.totalLoanAmount = totalLoanAmount;
        }

        public BigDecimal getTotalOutstandingAmount() {
            return totalOutstandingAmount;
        }

        public void setTotalOutstandingAmount(BigDecimal totalOutstandingAmount) {
            this.totalOutstandingAmount = totalOutstandingAmount;
        }

        public BigDecimal getHaohanOutstandingAmount() {
            return haohanOutstandingAmount;
        }

        public void setHaohanOutstandingAmount(BigDecimal haohanOutstandingAmount) {
            this.haohanOutstandingAmount = haohanOutstandingAmount;
        }

        public int getOrderCount() {
            return orderCount;
        }

        public void setOrderCount(int orderCount) {
            this.orderCount = orderCount;
        }
    }

    /**
     * 数据生成结果类
     */
    public static class DataGenerationResult {
        private List<CustomerInfo> customers;
        private List<CustomerOrder> orders;
        private List<CustomerRepayPlan> repayPlans;

        // Getters and Setters
        public List<CustomerInfo> getCustomers() {
            return customers;
        }

        public void setCustomers(List<CustomerInfo> customers) {
            this.customers = customers;
        }

        public List<CustomerOrder> getOrders() {
            return orders;
        }

        public void setOrders(List<CustomerOrder> orders) {
            this.orders = orders;
        }

        public List<CustomerRepayPlan> getRepayPlans() {
            return repayPlans;
        }

        public void setRepayPlans(List<CustomerRepayPlan> repayPlans) {
            this.repayPlans = repayPlans;
        }
    }

    /**
     * 生成脱敏手机号
     */
    public static String generateMaskedPhone() {
        String[] prefixes = {"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
                "150", "151", "152", "153", "155", "156", "157", "158", "159",
                "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "199"};

        String prefix = prefixes[random.nextInt(prefixes.length)];

        // 生成后4位数字
        String lastFour = String.format("%04d", random.nextInt(10000));

        // 脱敏格式：186****6454
        return prefix + "****" + lastFour;
    }

    /**
     * 生成脱敏身份证号
     */
    public static String generateMaskedIdNo(String fullCode, String gender) {
        // 使用完整的6位行政区划代码
//        String fullCode = CITY_CODE_MAP.getOrDefault(city, "110000"); // 默认北京

        // 截取前4位
        String prefix = fullCode.substring(0, 4);

        // 生成倒数第二位数字（根据性别：男性单数，女性双数）
        int secondLastDigit;
        if ("男".equals(gender)) {
            // 男性：生成单数（1,3,5,7,9）
            secondLastDigit = 1 + random.nextInt(5) * 2; // 1,3,5,7,9
        } else {
            // 女性：生成双数（0,2,4,6,8）
            secondLastDigit = random.nextInt(5) * 2; // 0,2,4,6,8
        }

        // 生成最后一位数字（0-9）
        int lastDigit = random.nextInt(10);

        // 生成倒数第三位数字（0-9）
        int thirdLastDigit = random.nextInt(10);

        // 生成倒数第四位数字（0-9）
        int fourthLastDigit = random.nextInt(10);

        // 组合后4位数字
        String lastFour = String.format("%d%d%d%d", fourthLastDigit, thirdLastDigit, secondLastDigit, lastDigit);

        // 脱敏格式：513822**********0061
        return prefix + "**********" + lastFour;
    }

    /**
     * 生成订单号
     */
    private static String generateOrderNo() {
        return "ORD" + System.currentTimeMillis() + String.format("%04d", random.nextInt(10000));
    }

    private void insertCustomers(List<CustomerInfo> customers) {
        customerInfoService.saveBatch(customers);
    }

    /**
     * 插入客户订单
     */
    private void insertOrders(List<CustomerOrder> orders) {
        customerOrderService.saveBatch(orders);
    }

    /**
     * 插入客户还款计划
     */
    private void insertRepayPlans(List<CustomerRepayPlan> repayPlans) {
        customerRepayPlanService.saveBatch(repayPlans);
    }

    /**
     * 分批插入客户信息，避免连接超时
     */
    private void insertCustomersInBatches(List<CustomerInfo> customers) {
        if (customers.isEmpty()) return;

        int batchSize = 2000; // 减小批次大小
        for (int i = 0; i < customers.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, customers.size());
            List<CustomerInfo> batch = customers.subList(i, endIndex);
            try {
                customerInfoService.saveBatch(batch);
                log.debug("插入客户信息批次 {}-{}", i, endIndex - 1);
            } catch (Exception e) {
                log.error("插入客户信息批次 {}-{} 失败", i, endIndex - 1, e);
            }
        }
    }

    /**
     * 分批插入订单，避免连接超时
     */
    private void insertOrdersInBatches(List<CustomerOrder> orders) {
        if (orders.isEmpty()) return;

        int batchSize = 2000; // 减小批次大小
        for (int i = 0; i < orders.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, orders.size());
            List<CustomerOrder> batch = orders.subList(i, endIndex);
            try {
                customerOrderService.saveBatch(batch);
                log.debug("插入订单批次 {}-{}", i, endIndex - 1);
            } catch (Exception e) {
                log.error("插入订单批次 {}-{} 失败", i, endIndex - 1, e);
                throw e;
            }
        }
    }

    /**
     * 分批插入还款计划，避免连接超时
     */
    private void insertRepayPlansInBatches(List<CustomerRepayPlan> repayPlans) {
        if (repayPlans.isEmpty()) return;

        int batchSize = 4000; // 还款计划数量通常较多，可以适当增大批次
        for (int i = 0; i < repayPlans.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, repayPlans.size());
            List<CustomerRepayPlan> batch = repayPlans.subList(i, endIndex);
            try {
                customerRepayPlanService.saveBatch(batch);
                log.debug("插入还款计划批次 {}-{}", i, endIndex - 1);
            } catch (Exception e) {
                log.error("插入还款计划批次 {}-{} 失败", i, endIndex - 1, e);
                throw e;
            }
        }
    }

    // 省份放款金额比例映射
    private static final Map<String, Double> PROVINCE_LOAN_RATIO = new HashMap<>();
    
    static {
        // 根据您提供的各省份放款金额比例初始化
        PROVINCE_LOAN_RATIO.put("安徽省", 0.0596);
        PROVINCE_LOAN_RATIO.put("北京市", 0.0325);
        PROVINCE_LOAN_RATIO.put("福建省", 0.0365);
        PROVINCE_LOAN_RATIO.put("甘肃省", 0.0142);
        PROVINCE_LOAN_RATIO.put("广东省", 0.1131);
        PROVINCE_LOAN_RATIO.put("广西壮族自治区", 0.0132);
        PROVINCE_LOAN_RATIO.put("贵州省", 0.0152);
        PROVINCE_LOAN_RATIO.put("海南省", 0.0079);
        PROVINCE_LOAN_RATIO.put("河北省", 0.0552);
        PROVINCE_LOAN_RATIO.put("河南省", 0.0384);
        PROVINCE_LOAN_RATIO.put("黑龙江省", 0.0179);
        PROVINCE_LOAN_RATIO.put("湖北省", 0.0253);
        PROVINCE_LOAN_RATIO.put("湖南省", 0.0310);
        PROVINCE_LOAN_RATIO.put("吉林省", 0.0145);
        PROVINCE_LOAN_RATIO.put("江苏省", 0.1238);
        PROVINCE_LOAN_RATIO.put("江西省", 0.0143);
        PROVINCE_LOAN_RATIO.put("辽宁省", 0.0330);
        PROVINCE_LOAN_RATIO.put("内蒙古自治区", 0.0144);
        PROVINCE_LOAN_RATIO.put("宁夏回族自治区", 0.0004);
        PROVINCE_LOAN_RATIO.put("青海省", 0.0007);
        PROVINCE_LOAN_RATIO.put("山东省", 0.0762);
        PROVINCE_LOAN_RATIO.put("山西省", 0.0211);
        PROVINCE_LOAN_RATIO.put("陕西省", 0.0297);
        PROVINCE_LOAN_RATIO.put("上海市", 0.0362);
        PROVINCE_LOAN_RATIO.put("四川省", 0.0455);
        PROVINCE_LOAN_RATIO.put("天津市", 0.0146);
        PROVINCE_LOAN_RATIO.put("云南省", 0.0209);
        PROVINCE_LOAN_RATIO.put("浙江省", 0.0788);
        PROVINCE_LOAN_RATIO.put("重庆市", 0.0161);
    }
    
    // 按照省份放款金额比例随机获取一个城市和对应的代码
    public static Map.Entry<String, String> getRandomCityCode() {
        if (CITY_CODE_MAP.isEmpty()) {
            return null;
        }
        
        // 生成0-1之间的随机数
        double randomValue = random.nextDouble();
        double cumulativeProbability = 0.0;
        
        // 按照省份比例选择城市
        for (Map.Entry<String, Double> provinceEntry : PROVINCE_LOAN_RATIO.entrySet()) {
            String province = provinceEntry.getKey();
            double ratio = provinceEntry.getValue();
            
            cumulativeProbability += ratio;
            
            if (randomValue <= cumulativeProbability) {
                // 找到对应的省份，从该省份的城市中随机选择一个
                List<Map.Entry<String, String>> provinceCities = new ArrayList<>();
                for (Map.Entry<String, String> cityEntry : CITY_CODE_MAP.entrySet()) {
                    String cityProvince = getProvinceByCity(cityEntry.getKey());
                    if (province.equals(cityProvince)) {
                        provinceCities.add(cityEntry);
                    }
                }
                
                if (!provinceCities.isEmpty()) {
                    return provinceCities.get(random.nextInt(provinceCities.size()));
                }
            }
        }
        
        // 如果上述逻辑失败，返回随机城市（兜底逻辑）
        List<Map.Entry<String, String>> entries = new ArrayList<>(CITY_CODE_MAP.entrySet());
        return entries.get(random.nextInt(entries.size()));
    }

    /**
     * 生成订单数据批次（多线程调用）
     */
    public OrderDataPackage generateOrderDataBatch(LocalDate month, int orderCount, int monthlyOrders) {
        OrderDataPackage orderPackage = new OrderDataPackage();

        // 使用产品分布逻辑生成该月数据
        Map<String, Integer> productDistribution = calculateProductDistribution(month, orderCount);

        int globalOrderIndex = 0; // 全局订单序号

        for (Map.Entry<String, Integer> entry : productDistribution.entrySet()) {
            String productName = entry.getKey();
            int productOrderCount = entry.getValue();

            for (int i = 0; i < productOrderCount; i++) {
                // 生成该月内随机的一天作为订单创建时间
                LocalDate randomDayInMonth = generateRandomDayInMonth(month);

                // 生成客户信息
                CustomerInfo customer = generateCustomerInfo(randomDayInMonth);

                // 生成订单（使用正确的产品名称和随机日期）
                CustomerOrder order = generateCustomerOrder(customer, randomDayInMonth, productName);
                order.setFrTime(customer.getCreatedTime().substring(0, 10));

                // 生成还款计划，传递全局订单序号
                List<CustomerRepayPlan> repayPlans = generateRepayPlan(order, monthlyOrders, globalOrderIndex);

                // 处理第1期已结清订单的逾期1-3天逻辑
                processFirstPeriodOverdueForSettledOrders(repayPlans, order, globalOrderIndex, monthlyOrders);

                // 设置订单客户ID
                order.setCustomerId(customer.getId());

                // 添加到数据包
                orderPackage.getCustomers().add(customer);
                orderPackage.getOrders().add(order);
                orderPackage.getRepayPlans().addAll(repayPlans);

                // 更新统计
                orderPackage.setTotalLoanAmount(orderPackage.getTotalLoanAmount().add(order.getLoanAmount()));
                if ("未结清".equals(order.getStatus())) {
                    orderPackage.setTotalOutstandingAmount(orderPackage.getTotalOutstandingAmount().add(order.getRemainPayAmount()));
                    if ("浩瀚小贷".equals(order.getProductName())) {
                        orderPackage.setHaohanOutstandingAmount(orderPackage.getHaohanOutstandingAmount().add(order.getRemainPayAmount()));
                    }
                }
                orderPackage.setOrderCount(orderPackage.getOrderCount() + 1);
                
                globalOrderIndex++; // 递增全局订单序号
            }
        }

        return orderPackage;
    }

    /**
     * 处理批量插入（线程安全）
     */
    private synchronized void processBatchInsert(List<CustomerInfo> customerBatch,
                                                 List<CustomerOrder> orderBatch,
                                                 List<CustomerRepayPlan> repayPlanBatch,
                                                 AtomicInteger batchCount,
                                                 AtomicInteger totalProcessedOrders,
                                                 AtomicReference<BigDecimal> totalGeneratedAmount,
                                                 AtomicReference<BigDecimal> totalOutstandingAmount) {
        if (customerBatch.isEmpty()) {
            return;
        }

        int currentBatchCount = batchCount.incrementAndGet();
        log.info("开始批量插入第 {} 批数据，共 {} 条用户信息", currentBatchCount, customerBatch.size());

        long batchStartTime = System.currentTimeMillis();
        batchInsertDataBatch(new ArrayList<>(customerBatch), new ArrayList<>(orderBatch), new ArrayList<>(repayPlanBatch));
        long batchEndTime = System.currentTimeMillis();

        log.info("第 {} 批数据插入完成，耗时: {} 毫秒", currentBatchCount, (batchEndTime - batchStartTime));
        log.info("已处理 {} 条订单", totalProcessedOrders.get());
        log.info("当前总投放金额: {} 亿", totalGeneratedAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));
        log.info("当前在途余额: {} 亿", totalOutstandingAmount.get().divide(new BigDecimal("100000000"), 2, RoundingMode.HALF_UP));

        // 清空批量插入缓存
        customerBatch.clear();
        orderBatch.clear();
        repayPlanBatch.clear();
    }

    /**
     * 根据dueDate年月和billTenor期数，按比例选择逾期天数区间
     * 逾期天数分布：
     * 1-7天：5%
     * 7-15天：3%
     * 15-30天：2%
     * 30-60天：1.5%
     * 60-90天：1.2%
     * 90-120天：1%
     * 120-150天：0.8%
     * 150-180天：0.7%
     * 180-210天：0.6%
     * 210-240天：0.5%
     * 240-270天：0.4%
     * 270-300天：0.3%
     * 300-330天：0.2%
     * 330-360天：0.2%
     * 360-390天：0.2%
     * 390-420天：0.2%
     * 420-450天：0.2%
     * 450-480天：0.2%
     * 480-510天：0.2%
     * 510-540天：0.2%
     * 540-570天：0.2%
     * 570-600天：0.2%
     * 600-630天：0.2%
     * 630-660天：0.2%
     * 660-690天：0.2%
     * 690-720天：0.2%
     * 720-750天：0.2%
     * 750-780天：0.2%
     * 780-810天：0.2%
     * 810-820天：0.2%
     * @param dueDate 应还款日期
     * @param billTenor 期数
     * @param monthlyOrders 当月订单总数
     * @return 逾期天数区间的标识符
     */
    /**
     * 根据dueDate年月和billTenor期数，按比例选择逾期天数区间
     * 使用OVERDAY映射中的百分比分布：
     * D1_7: 5%
     * D7_15: 3%
     * D15_30: 2%
     * NORMAL: 90%
     *
     * @param dueDate       应还款日期
     * @param billTenor     期数
     * @param monthlyOrders 当月订单总数
     * @return 逾期天数区间的标识符
     */
    private static String selectOverdueDaysBucketByDueDateAndBillTenor(LocalDate dueDate, Long billTenor, int monthlyOrders) {
        // 从dueDate提取年月信息作为分布依据
        String yearMonth = dueDate.toString().substring(0, 7); // 提取"2023-07"

        // 将年月和期数转换为数字
        String year = yearMonth.substring(0, 4);
        String month = yearMonth.substring(5, 7);
        int yearInt = Integer.parseInt(year);
        int monthInt = Integer.parseInt(month);
        int billTenorInt = billTenor.intValue();

        // 使用年月和期数生成稳定的随机数，确保每个月都有相同的分布
        long seed = (yearInt * 10000L + monthInt * 100L + billTenorInt) % 10007;
        double randomValue = (seed % 10000) / 10000.0;

        // 按照OVERDAY映射中的百分比分配逾期天数区间
        double cumulative = 0.0;

        // D1_7: 5%
        cumulative += OVERDAY.get("D1_7");
        if (randomValue < cumulative) {
            return "D1_7";
        }

        // D7_15: 3%
        cumulative += OVERDAY.get("D7_15");
        if (randomValue < cumulative) {
            return "D7_15";
        }

        // D15_30: 2%
        cumulative += OVERDAY.get("D15_30");
        if (randomValue < cumulative) {
            return "D15_30";
        }
        cumulative += OVERDAY.get("D30_45");
        if (randomValue < cumulative) {
            return "D30_45";
        }


        // NORMAL: 90% (剩余部分)
        return "NORMAL";
    }

    /**
     * 根据逾期天数区间计算实际逾期天数
     *
     * @param bucket 逾期天数区间标识符
     * @return 实际逾期天数
     */
    private static int calculateActualOverdueDays(String bucket) {
        switch (bucket) {
            case "D1_4":
                    return 1 + random.nextInt(4);     // 1-3天
            case "D4_7":
                return 4 + random.nextInt(7);     // 1-7天
            case "D7_15":
                return 7 + random.nextInt(9);     // 7-15天
            case "D15_30":
                return 15 + random.nextInt(16);   // 15-30天
            case "D30_60":
                return 30 + random.nextInt(31);   // 30-60天
            case "D60_90":
                return 60 + random.nextInt(31);   // 60-90天
            case "D90_120":
                return 90 + random.nextInt(31);   // 90-120天
            case "D120_150":
                return 120 + random.nextInt(31);  // 120-150天
            case "D150_180":
                return 150 + random.nextInt(31);  // 150-180天
            case "D180_210":
                return 180 + random.nextInt(31);  // 180-210天
            case "D210_240":
                return 210 + random.nextInt(31);  // 210-240天
            case "D240_270":
                return 240 + random.nextInt(31);  // 240-270天
            case "D270_300":
                return 270 + random.nextInt(31);  // 270-300天
            case "D300_330":
                return 300 + random.nextInt(31);  // 300-330天
            case "D330_360":
                return 330 + random.nextInt(31);  // 330-360天
            case "D360_390":
                return 360 + random.nextInt(31);  // 360-390天
            case "D390_420":
                return 390 + random.nextInt(31);  // 390-420天
            case "D420_450":
                return 420 + random.nextInt(31);  // 420-450天
            case "D450_480":
                return 450 + random.nextInt(31);  // 450-480天
            case "D480_510":
                return 480 + random.nextInt(31);  // 480-510天
            case "D510_540":
                return 510 + random.nextInt(31);  // 510-540天
            case "D540_570":
                return 540 + random.nextInt(31);  // 540-570天
            case "D570_600":
                return 570 + random.nextInt(31);  // 570-600天
            case "D600_630":
                return 600 + random.nextInt(31);  // 600-630天
            case "D630_660":
                return 630 + random.nextInt(31);  // 630-660天
            case "D660_690":
                return 660 + random.nextInt(31);  // 660-690天
            case "D690_720":
                return 690 + random.nextInt(31);  // 690-720天
            case "D720_750":
                return 720 + random.nextInt(31);  // 720-750天
            case "D750_780":
                return 750 + random.nextInt(31);  // 750-780天
            case "D780_810":
                return 780 + random.nextInt(31);  // 780-810天
            case "D810_820":
                return 810 + random.nextInt(11);  // 810-820天
            default:
                return 0; // 无逾期
        }
    }

    /**
     * 生成基于期数爬坡的均匀分布随机数
     * 期数越大，逾期率越高（爬坡逻辑）
     */
    private static double generateUniformRandomFromLoanDateOrderNoAndTerm(LocalDate loanDate, String orderNo, int term) {
        // 策略1：使用日期的多个组成部分
        int year = loanDate.getYear();
        int month = loanDate.getMonthValue();
        int day = loanDate.getDayOfMonth();
        int dayOfYear = loanDate.getDayOfYear();

        // 策略2：计算从基准日期（2023-01-01）开始的天数，确保时间递增性
        LocalDate baseDate = LocalDate.of(2023, 1, 1);
        long daysFromBase = ChronoUnit.DAYS.between(baseDate, loanDate);

        // 策略3：使用订单号的哈希值，确保递增订单号也能产生均匀分布
        long orderHash = Math.abs(orderNo.hashCode());

        // 策略4：使用订单号的数字部分增加变化
        String orderNoDigits = orderNo.replaceAll("[^0-9]", ""); // 提取数字部分
        long orderNoNumeric = orderNoDigits.isEmpty() ? 0 : Long.parseLong(orderNoDigits.substring(0, Math.min(8, orderNoDigits.length())));

        // 策略5：使用多个不同的质数进行取模运算，结合日期、订单号和期数信息
        long num1 = (daysFromBase * 10000L + year * 100L + month + orderHash + term * 1000L) % 10007; // 质数10007
        long num2 = (dayOfYear * 1000L + month * 100L + day + orderHash + term * 100L) % 9973;  // 质数9973
        long num3 = (year * 1000L + dayOfYear + orderNoNumeric + term * 10L) % 9923;  // 质数9923
        long num4 = (num1 + orderNoNumeric + orderHash + term) % 9901; // 质数9901

        // 策略6：使用位运算和异或操作增加随机性
        long mixed = (num1 ^ num2 ^ num3 ^ num4) & 0x7FFFFFFF; // 确保为正数

        // 策略7：使用正弦函数进一步打乱分布
        double sinValue = Math.sin(mixed * 0.0001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]

        // 策略8：添加微小的日期变化因子（不累积）
        // 使用取模确保不会随时间持续增长
        double dateVariation = ((daysFromBase % 365) / 365.0) * 0.03; // 限制在3%影响
        double monthVariation = ((month - 1) / 12.0) * 0.02; // 限制在2%影响，从0开始避免偏差

        // 策略9：使用订单号创建不同的偏移量，确保不同订单号的分布错开
        double orderOffset1 = (orderNoNumeric % 1000) / 1000.0 * 0.05; // 5%的影响，基于订单号数字
        double orderOffset2 = (orderHash % 1000) / 1000.0 * 0.05; // 5%的影响，基于订单号哈希

        // 策略10：期数爬坡逻辑 - 期数越大，逾期率越高（这是唯一应该有方向性增长的因素）
        double termInfluence = calculateTermInfluence(term);

        // 最终结果：混合所有策略
        // 注意：只有termInfluence是方向性增长，其他都是循环变化，确保时间维度的均匀分布
        double result = (normalized + dateVariation + monthVariation + orderOffset1 + orderOffset2 + termInfluence) % 1.0;

        return result;
    }

    /**
     * 计算期数对逾期率的影响（爬坡逻辑）
     * 期数越大，逾期率越高
     */
    private static double calculateTermInfluence(int term) {
        // 期数爬坡逻辑：
        // 3期：基础逾期率 3%
        // 6期：基础逾期率 6% 
        // 12期：基础逾期率 12%
        // 18期：基础逾期率 18%
        // 24期：基础逾期率 24%
        
        double baseOverdueRate;
        switch (term) {
            case 3:
                baseOverdueRate = 0.03; // 3%
                break;
            case 6:
                baseOverdueRate = 0.06; // 6%
                break;
            case 12:
                baseOverdueRate = 0.12; // 12%
                break;
            case 18:
                baseOverdueRate = 0.18; // 18%
                break;
            case 24:
                baseOverdueRate = 0.24; // 24%
                break;
            default:
                // 对于其他期数，使用线性插值
                if (term < 3) {
                    baseOverdueRate = 0.01; // 1期、2期：1%
                } else if (term > 24) {
                    baseOverdueRate = 0.30; // 超过24期：30%
                } else {
                    // 线性插值：3期=3%，24期=24%
                    baseOverdueRate = 0.03 + (term - 3) * (0.24 - 0.03) / (24 - 3);
                }
                break;
        }
        
        // 将逾期率转换为影响因子（0-0.3的范围）
        return baseOverdueRate * 0.3; // 最大30%的影响
    }
    /**
     * 基于monthlyOrders判断第一期是否应该逾期，确保每月订单的10%左右逾期
     * 结合期数判断，只有第一期才可能逾期
     */
    private static boolean shouldFirstPeriodOverdueByMonthlyOrders(int monthlyOrders, Long billTenor) {
        if (billTenor != 1) {
            return false; // 只有第一期才可能逾期
        }
        
        // 使用monthlyOrders生成均匀分布的随机数
        // 使用质数确保分布均匀性
        long orderHash = (monthlyOrders * 10007L) % 10007; // 质数10007
        
        // 使用正弦函数将订单数映射到[0,1]区间
        double sinValue = Math.sin(orderHash * 0.001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]
        
        // 添加基于订单数的偏移量，确保不同订单数的分布错开
        double orderOffset = (monthlyOrders * 0.01) % 1.0;
        double finalValue = (normalized + orderOffset) % 1.0;
        
        // 10%的概率逾期
        return finalValue < 0.10;
    }

    /**
     * 基于订单序号和月度订单总数判断第一期是否应该逾期1-3天
     * 确保第1期已还订单中逾期1-3天的订单占每个月总订单的9%左右
     * 使用订单序号确保精确控制逾期比例
     */
    private static boolean shouldFirstPeriodOverdue1To3Days(int orderIndex, int monthlyOrders, Long billTenor) {
        if (billTenor != 1) {
            return false; // 只有第一期才可能逾期
        }
        
        // 计算逾期订单数量：每月总订单的9%
        int overdueOrderCount = (int) Math.round(monthlyOrders * 0.09);
        
        // 使用更稳定的哈希算法，确保分布均匀
        // 使用质数确保分布均匀性，避免周期性模式
        long hashValue = ((long) orderIndex * 10007L + monthlyOrders * 9973L) % 10007;
        
        // 将哈希值映射到[0, monthlyOrders)区间
        int mappedIndex = (int) (hashValue % monthlyOrders);
        
        // 如果映射的索引在逾期订单数量范围内，则该订单逾期
        return mappedIndex < overdueOrderCount;
    }

    // 记录每个月第一期逾期1到3天的订单数和比例
    private static final Map<String, OverdueStats> monthlyOverdueStats = new ConcurrentHashMap<>();
    
    /**
     * 逾期统计信息
     */
    private static class OverdueStats {
        private final int totalOrders;           // 总订单数
        private final int targetOverdueCount;    // 目标逾期订单数（7%）
        private final AtomicInteger currentOverdueCount = new AtomicInteger(0); // 当前已逾期订单数
        private final AtomicInteger processedOrders = new AtomicInteger(0);     // 已处理订单数
        
        public OverdueStats(int totalOrders) {
            this.totalOrders = totalOrders;
            this.targetOverdueCount = (int) Math.round(totalOrders * 0.07);//这个参数调整的是首逾1+FPD的大小
        }
        
        public boolean shouldOverdue() {
            int processed = processedOrders.incrementAndGet();
            int currentOverdue = currentOverdueCount.get();
            
            // 如果已经达到目标逾期数量，不再逾期
            if (currentOverdue >= targetOverdueCount) {
                return false;
            }
            
            // 如果剩余订单数不足以达到目标逾期数量，必须逾期
            int remainingOrders = totalOrders - processed;
            int remainingOverdueNeeded = targetOverdueCount - currentOverdue;
            if (remainingOrders <= remainingOverdueNeeded) {
                currentOverdueCount.incrementAndGet();
                return true;
            }
            
            // 计算当前逾期率
            double currentOverdueRate = (double) currentOverdue / processed;
            double targetOverdueRate = 0.07;//这个参数调整的是首逾1+FPD的大小
            
            // 如果当前逾期率低于目标，增加逾期概率
            if (currentOverdueRate < targetOverdueRate) {
                // 计算需要逾期的概率
                double overdueProbability = (targetOverdueRate - currentOverdueRate) * 2;
                if (Math.random() < overdueProbability) {
                    currentOverdueCount.incrementAndGet();
                    return true;
                }
            }
            
            return false;
        }
        
        public String getStats() {
            return String.format("*****************总订单:%d, 目标逾期:%d, 当前逾期:%d, 已处理:%d, 逾期率:%.2f%%*****************",
                    totalOrders, targetOverdueCount, currentOverdueCount.get(), 
                    processedOrders.get(), (double) currentOverdueCount.get() / processedOrders.get() * 100);
        }
    }

    /**
     * 基于放款时间和月度订单数判断第一期已结清订单是否应该逾期1-3天
     * 使用统计参数确保每月逾期率稳定在9%左右
     */
    private static boolean shouldFirstPeriodSettledOrderOverdue(String frTime, int monthlyOrders) {
        try {
            // 解析放款时间获取年月
            LocalDate frDate = LocalDate.parse(frTime);
            int year = frDate.getYear();
            int month = frDate.getMonthValue();
            
            // 生成月份键
            String monthKey = year + "-" + String.format("%02d", month);
            
            // 获取或创建该月的逾期统计
            OverdueStats stats = monthlyOverdueStats.computeIfAbsent(monthKey, k -> new OverdueStats(monthlyOrders));
            
            // 使用统计参数判断是否应该逾期
            boolean shouldOverdue = stats.shouldOverdue();
            
            // 记录统计信息（每100个订单记录一次）
            if (stats.processedOrders.get() % 100 == 0) {
                log.info("===========月份 {} 逾期统计: {}======", monthKey, stats.getStats());
            }
            
            return shouldOverdue;
            
        } catch (Exception e) {
            log.error("判断逾期状态失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 处理第1期已结清订单的逾期1-3天逻辑
     * 确保第1期已还订单中逾期1-3天的订单占每个月总订单的9%左右
     */
    private static void processFirstPeriodOverdueForSettledOrders(List<CustomerRepayPlan> repayPlans, 
                                                                 CustomerOrder order, 
                                                                 int orderIndex, 
                                                                 int monthlyOrders) {
        if (repayPlans.isEmpty()) return;
        
        // 找到第1期还款计划
        CustomerRepayPlan firstPeriodPlan = repayPlans.stream()
                .filter(plan -> plan.getBillTenor() == 1)
                .findFirst()
                .orElse(null);
        
        if (firstPeriodPlan == null) return;
        
        // 只有第1期状态是"已结清"的订单才处理
        if (!"已结清".equals(firstPeriodPlan.getRepayStatus())) {
            return;
        }
        
        LocalDate maxRepayDate = LocalDate.of(2025, 9, 30);
        
        // 判断该订单是否应该逾期1-3天
        if (shouldFirstPeriodSettledOrderOverdue(order.getFrTime(), monthlyOrders)) {
//            log.info("放款时间{}，期数{}------------------**************===========", order.getFrTime(), firstPeriodPlan.getBillTenor());
            // 设置逾期1-3天
            int overdueDays = 1 + random.nextInt(3); // 1-3天
            LocalDate dueDate = firstPeriodPlan.getDueDate();
            LocalDate actualRepayDate = dueDate.plusDays(overdueDays);
            // 确保实际还款日期不超过最大还款日期
            if (actualRepayDate.isAfter(maxRepayDate)) {
                actualRepayDate = maxRepayDate;
                overdueDays = (int) (actualRepayDate.toEpochDay() - dueDate.toEpochDay());
            }
            
            // 更新第1期还款计划
            firstPeriodPlan.setActualRepayDate(actualRepayDate);
            firstPeriodPlan.setOverdueDays(overdueDays);
            
            // 计算罚息（如果逾期超过3天）
            if (overdueDays > 3) {
                BigDecimal penaltyRate = firstPeriodPlan.getRate().divide(new BigDecimal("365"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("1.5"));
                BigDecimal penaltyInterest = firstPeriodPlan.getNowPayAmount()
                        .multiply(penaltyRate)
                        .multiply(BigDecimal.valueOf(overdueDays));
                firstPeriodPlan.setPenaltyInterest(penaltyInterest);
            }
            
//            log.info("第1期已结清订单逾期处理 - 订单号: {}, 期数: {}, 逾期天数: {}",
//                    order.getOrderNo(), firstPeriodPlan.getBillTenor(), overdueDays);
        }
    }

    /**
     * 基于frTime判断第一期是否应该逾期，确保每年和每月都有15%的订单逾期，均匀分布
     * 不需要根据orderNo来，单纯基于年月信息
     */
    private static boolean shouldFirstPeriodOverdueByFrTimeOnly(String frTime) {
        try {
            // 解析frTime为LocalDate
            LocalDate frDate = LocalDate.parse(frTime);
            int year = frDate.getYear();
            int month = frDate.getMonthValue();
            
            // 使用年月信息生成均匀分布的随机数
            // 使用质数确保分布均匀性
            long yearMonthHash = (year * 12L + month) % 10007; // 质数10007
            
            // 使用正弦函数将年月信息映射到[0,1]区间
            double sinValue = Math.sin(yearMonthHash * 0.001);
            double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]
            
            // 添加基于年份的偏移量，确保不同年份的分布错开
            double yearOffset = (year * 0.01) % 1.0;
            double finalValue = (normalized + yearOffset) % 1.0;
            
            // 15%的概率逾期
            return finalValue < 0.28;
            
        } catch (Exception e) {
            // 如果解析失败，使用年月作为备选方案
            try {
                LocalDate frDate = LocalDate.parse(frTime);
                int year = frDate.getYear();
                int month = frDate.getMonthValue();
                return ((year * 12 + month) % 100) <28;//15%的概率
            } catch (Exception ex) {
                return false; // 解析失败，默认不逾期
            }
        }
    }

    private static double generateUniformRandomFromLoanDateAndOrderNo(LocalDate loanDate, String orderNo) {
        // 策略1：使用日期的多个组成部分
        int year = loanDate.getYear();
        int month = loanDate.getMonthValue();
        int day = loanDate.getDayOfMonth();
        int dayOfYear = loanDate.getDayOfYear();

        // 策略2：计算从基准日期（2023-01-01）开始的天数，确保时间递增性
        LocalDate baseDate = LocalDate.of(2023, 1, 1);
        long daysFromBase = ChronoUnit.DAYS.between(baseDate, loanDate);

        // 策略3：使用订单号的哈希值，确保递增订单号也能产生均匀分布
        long orderHash = Math.abs(orderNo.hashCode());

        // 策略4：使用订单号的数字部分增加变化
        String orderNoDigits = orderNo.replaceAll("[^0-9]", ""); // 提取数字部分
        long orderNoNumeric = orderNoDigits.isEmpty() ? 0 : Long.parseLong(orderNoDigits.substring(0, Math.min(8, orderNoDigits.length())));

        // 策略5：使用多个不同的质数进行取模运算，结合日期和订单号信息
        long num1 = (daysFromBase * 10000L + year * 100L + month + orderHash) % 10007; // 质数10007
        long num2 = (dayOfYear * 1000L + month * 100L + day + orderHash) % 9973;  // 质数9973
        long num3 = (year * 1000L + dayOfYear + orderNoNumeric) % 9923;  // 质数9923
        long num4 = (num1 + orderNoNumeric + orderHash) % 9901; // 质数9901

        // 策略6：使用位运算和异或操作增加随机性
        long mixed = (num1 ^ num2 ^ num3 ^ num4) & 0x7FFFFFFF; // 确保为正数

        // 策略7：使用正弦函数进一步打乱分布
        double sinValue = Math.sin(mixed * 0.0001);
        double normalized = (sinValue + 1.0) / 2.0; // 将[-1,1]映射到[0,1]

        // 策略8：添加基于日期的递增偏移量，确保时间序列的连续性
        double dateIncrement = (daysFromBase % 365) / 365.0 * 0.1; // 基于天数的10%影响
        double yearInfluence = (year % 100) / 100.0 * 0.05; // 5%的年份影响
        double monthInfluence = (month / 12.0) * 0.05; // 5%的月份影响

        // 策略9：使用订单号创建不同的偏移量，确保不同订单号的分布错开
        double orderOffset1 = (orderNoNumeric % 1000) / 1000.0 * 0.1; // 10%的影响，基于订单号数字
        double orderOffset2 = (orderHash % 1000) / 1000.0 * 0.1; // 10%的影响，基于订单号哈希

        // 最终结果：混合所有策略，加入日期递增偏移
        double result = (normalized + dateIncrement + yearInfluence + monthInfluence + orderOffset1 + orderOffset2) % 1.0;

        return result;
    }


}
